简体   繁体   中英

Is there a way to find all HTML elements that use viewport units in their styles?

I'm building an editor tool that for some features it needs to resize / zoom out the viewport to show more sections on the page.

I don't control the input of HTML/CSS/JS All the CSS is external CSS from a link tag

The problem is HTML elements using vh as height or min-height in their styles.

is it possible to search the DOM for elements that have vh styles assigned?

I tried using getComputedStyle but as the function name suggests, it returns "computed" styles so for example if I have a section with height of 80vh

getComputedStyle(el).height
// will return the computed value which is on my screen "655.2px"

What I'm hoping to achieve is to find those elements and assign them the computed values temporarily during the "zoomed out" view.

As i mentioned above the styles are external so using the style property won't provide what I'm looking for.

After some research and thanks to fubar's comment for pointing me to an answer using document.styleSheets I was able to come up with a solution that fulfils my need.

function findVhElements() {
    const stylesheets = Array.from(document.styleSheets)
    const hasVh = str => str.includes('vh');
    // this reducer returns an array of elements that use VH in their height or min-height properties 
    return stylesheets.reduce( (acc,sheet) => { 
        // Browsers block your access to css rules if the stylesheet is from a different origin without proper allow-access-control-origin http header
        // therefore I skip those stylesheets 
        if (!sheet.href || !sheet.href.includes(location.origin)) return acc
        // find rules that use 'vh' in either 'minHeight' or 'height' properties
        const targetRules = Array.from(sheet.rules).filter( ({style}) => style && (hasVh(style.minHeight) || hasVh(style.height)) )
        // skip if non were found
        if (!targetRules.length) return acc;
        // return elements based on the rule's selector that exits on the current document 
        return acc.concat(targetRules.map( ({selectorText}) =>  document.querySelector(selectorText) ).filter( el => el) ) 
    }, [])
}

This solution works for my case because the styles are coming from the same origin as the script, if you are dealing with styles from other origins I would suggest either implementing a backend solution or making sure that the other origin is providing HTTP headers that allows you to fetch it's content

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM