CSS改编/网页响应式 适配工作者

给CSS适配人员用的辅助工具函数

As of 06.02.2022. See ბოლო ვერსია.

ეს სკრიპტი არ უნდა იყოს პირდაპირ დაინსტალირებული. ეს ბიბლიოთეკაა, სხვა სკრიპტებისთვის უნდა ჩართეთ მეტა-დირექტივაში // @require https://update.greatest.deepsurf.us/scripts/439632/1015904/CSS%E6%94%B9%E7%BC%96%E7%BD%91%E9%A1%B5%E5%93%8D%E5%BA%94%E5%BC%8F%20%E9%80%82%E9%85%8D%E5%B7%A5%E4%BD%9C%E8%80%85.js.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

  1. // ==UserScript==
  2. // @name CSS改编/网页响应式 适配工作者
  3. // @version 0.55
  4. // @description 给CSS适配人员用的辅助工具函数
  5. // @description:en Helper functions for adaptation developers
  6. // @match *://*/*
  7. // @license The Unlicense
  8. // @namespace https://greatest.deepsurf.us/users/871942
  9. // ==/UserScript==
  10.  
  11.  
  12. function extract_those_elements_whose_attributes_include_styles(doc = document, filterAttr) {
  13. const elems = []
  14. elems.push(...[...doc.all].filter(el => (!filterAttr || el.hasAttribute(filterAttr)) && !/\b(a|img|span)\b/.test(el.localName) && (el.localName === 'iframe' ? elems.push(...extract_those_elements_whose_attributes_include_styles(el.contentDocument)) && false : el.attributes.style?.value)))
  15. return elems
  16. }
  17. function extractStyleToCssForm(elem) {
  18. let { localName, attributes: { id = '', class: className = '', style } } = elem
  19. if (specTags.has(localName)) {
  20. id = className = ''
  21. } else {
  22. localName = ''
  23. if (className) className = className.value.replace(/ |^/g, '.')
  24. if (id) {
  25. id = /[-]|auto|\bid\b/.test(id.value) ? '' : `#${id.value}`
  26. if (id) className = ''
  27. }
  28. }
  29. return `${localName}${id}${className} { ${style.value.replace(/(:) /g, '$1').replace(/;\b/g, '$& ').replace(/;$/, '')} }`
  30. }
  31. const specTags = new Set(['body'])
  32. unsafeWindow._extractCssOfModifiedInPage =
  33. function extractCssOfModifiedInPage(doc, { filterAttr = '', existing = 'user-custom' } = {}) {
  34. doc = doc.getRootNode() // `doc` can be an arbitrarily selected leaf node without having to pay attention to selecting `HTMLDocument`
  35. let orig = existing && doc instanceof Node && doc.querySelector(`style[${existing}]`)?.innerText || ''
  36. , new_ = extract_those_elements_whose_attributes_include_styles(doc, filterAttr).map(extractStyleToCssForm).join('\n')
  37. return { modified: mergeCommonCss(new_), merged: mergeCommonCss(orig + new_) }
  38. }
  39. function mergeCommonCss(css = '') {
  40. const re = {
  41. node: [/^(\s*)([^{}}]+)\s*\{([^}]+?)\s*\}(.*?)\2\{([^}]+?)\s*\}/ms, '$1$2{$3;$5 }$4'],
  42. nodes: [/([^{\n]+?)(\s*\{[^}]+\})(.*?)\s*([^{\n]+?)\2/s, '$1, $4$2$3']
  43. }
  44. let merged
  45. Object.values(re).forEach(([mat, pla]) => {
  46. const merge = str => str.replace(mat, pla)
  47. merged = merge(css)
  48. while (css !== merged) merged = merge(css = merged)
  49. })
  50. return merged
  51. }
  52.  
  53. unsafeWindow._findOverflowedElems =
  54. function findOverflowedElems(rootElem) {
  55. if (!(rootElem instanceof HTMLElement)) throw TypeError('An entry element is required to be specified.')
  56. return [...rootElem.querySelectorAll('*')].filter(el => el.clientWidth > rootElem.clientWidth)
  57. }