惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
PCI Perspectives
PCI Perspectives
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Google Online Security Blog
Google Online Security Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
The GitHub Blog
The GitHub Blog
S
Secure Thoughts
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
WordPress大学
WordPress大学
SecWiki News
SecWiki News
B
Blog
小众软件
小众软件
Hacker News - Newest:
Hacker News - Newest: "LLM"
Webroot Blog
Webroot Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
L
LINUX DO - 热门话题
Recent Commits to openclaw:main
Recent Commits to openclaw:main
酷 壳 – CoolShell
酷 壳 – CoolShell
IT之家
IT之家
The Cloudflare Blog
Google DeepMind News
Google DeepMind News
Know Your Adversary
Know Your Adversary
Y
Y Combinator Blog
F
Fortinet All Blogs
W
WeLiveSecurity
博客园 - Franky
MongoDB | Blog
MongoDB | Blog
Last Week in AI
Last Week in AI
The Last Watchdog
The Last Watchdog
S
Schneier on Security
爱范儿
爱范儿
V
V2EX - 技术
L
LINUX DO - 最新话题
月光博客
月光博客
博客园 - 【当耐特】
Latest news
Latest news
阮一峰的网络日志
阮一峰的网络日志
博客园 - 司徒正美
U
Unit 42
Schneier on Security
Schneier on Security
E
Exploit-DB.com RSS Feed
J
Java Code Geeks
Cyberwarzone
Cyberwarzone
T
The Blog of Author Tim Ferriss
TaoSecurity Blog
TaoSecurity Blog
博客园 - 叶小钗
T
Troy Hunt's Blog
大猫的无限游戏
大猫的无限游戏
AI
AI
Security Latest
Security Latest

Matthias Ott

Hello Again, World This, Still Not for Everyone The Shape of Friction WeissKlang L1 – Punching Above Its Weight Continvoucly Morged Value Webspace Invaders To Affinity and Beyond The Mystery of Storytelling Amateurs! Echoes of Connection Linear() Is Not (That) Linear View Transitions: The Smooth Parts Adding AVIF and WebP Support to My Craft CMS Site Challenge Acoustic Room Treatment and Building Sound Panels, Part 1: Planning Play On Overshoot The HTML Output Element Listening Closely Compressed Fluid Typography The Lifeblood of the Web What Could Go Wrong? That’s My Rank Making Space CSS :is() :where() the Magic Happens Visual Regression Testing for External URLs With Playwright Jane Goodall’s Famous Last Words European Tech Alternatives 🇪🇺 Independent Type Foundry Advent Calendar – Day 24: NaN Independent Type Foundry Advent Calendar – Day 23: Typotheque Independent Type Foundry Advent Calendar – Day 22: 205TF Independent Type Foundry Advent Calendar – Day 21: HvD Fonts Independent Type Foundry Advent Calendar – Day 20: Frere-Jones Type Independent Type Foundry Advent Calendar – Day 19: Fontwerk Independent Type Foundry Advent Calendar – Day 18: Vectro Independent Type Foundry Advent Calendar – Day 17: Studio René Bieder Independent Type Foundry Advent Calendar – Day 16: R-Typography Independent Type Foundry Advent Calendar – Day 15: David Jonathan Ross Independent Type Foundry Advent Calendar – Day 14: Interval Type Independent Type Foundry Advent Calendar – Day 13: Newglyph Independent Type Foundry Advent Calendar – Day 12: Swiss Typefaces Independent Type Foundry Advent Calendar – Day 11: Sharp Type Independent Type Foundry Advent Calendar – Day 10: Colophon Foundry Independent Type Foundry Advent Calendar – Day 9: Commercial Type Independent Type Foundry Advent Calendar – Day 8: Letters from Sweden Independent Type Foundry Advent Calendar – Day 7: Lineto Independent Type Foundry Advent Calendar – Day 6: Ohno Type Company Independent Type Foundry Advent Calendar – Day 5: Milieu Grotesque Independent Type Foundry Advent Calendar – Day 4: TypeMates Independent Type Foundry Advent Calendar – Day 3: Klim Type Foundry Independent Type Foundry Advent Calendar – Day 2: Dinamo Independent Type Foundry Advent Calendar – Day 1: Grilli Type The Independent Type Foundry Advent Calendar 2022 A Conversation With ChatGPT ChatGPT, please explain websites in the words of William Shakespeare Transient Frameworks Leaving Twitter Behind Converting Your Twitter Archive to Markdown The Wrong Question It Wasn’t Written Syndicating Posts from Your Personal Website to Twitter and Mastodon Suspension None of Your Business Doing Our Part Patch That Package Brain Dump Generating Accessibility Test Results for a Whole Website With Evaluatory The CSS Cascade, a Deep Dive Updates About Updates How to Delete Your Commit History in Git Unblocking Your Writing Blocks, Part 2: I’m Not an Expert nor a “Thought Leader” Connections No Wrong Notes Better Options Design Debt Finite and Infinite Games Don’t Assume, Validate. Necessity Is the Ultimate Teacher One Egg Go Deep There Is No Secret Code Balancing Risk Blue Eyes, Brown Eyes The Shortcut Boomerang My RSS Feed Collection of Personal Websites Frequency The Illusion of Control The Decisions Journey Write It Down Nownownow Into the Personal-Website-Verse Considering the Opposite What is it for? Unlimited Bowling. Never done. We Are Team Internet. We Need to Save #NetNeutrality. Progressive Search Data loss (also) by JavaScript Books I Will Definitely Maybe Read in 2017 Starting to Write Notes
Detecting CSS Selector Support with JavaScript
Matthias Ott · 2022-07-29 · via Matthias Ott

There are many ways to adjust your CSS code to a browser’s support for a specific CSS feature. If you want to check if a certain property is supported, you can write a feature query using the @supports at-rule, for example:

@supports (display: grid) {
  div {
    display: grid;
  }
}

If the browser supports display: grid, it will apply all the styles inside of the at-rule. Otherwise, it will just ignore the whole block.

If you want to check for support of a whole selector, you can use the @supports selector() function, which has surprisingly good browser support.

@supports selector(:nth-child(1 of .class)) {
	/* Do something… */
}

In case you want to learn more, Chris Coyier also wrote a nice piece about how to use @supports selector().

In a current project, however, I ran into a situation where I needed to test for support of the relatively new :where() selector. The tricky situation: both :where() and @supports selector() landed in browsers at about the same time, so if you want to check for support in an older browser, like Safari 13, you’re out of luck. Providing a sensible fallback for older browsers was one of the requirements, though, so I had to look for an alternative. And in the end, I decided to use JavaScript.

I found the solution in a post by Lea Verou. In 2011, she wrote about how to test for CSS selector support by creating a new <style> element with the selector we want to test for and then reading out the stylesheet to see if the rule actually exists. A really smart solution to detect support even in browsers <IE8.

But she also mentioned a much simpler solution: Using document.querySelector() in a try...catch statement. And since support for the Selectors API is very good these days, I settled on trying this. And it is indeed straightforward:

try {
    document.querySelector(selector)
} catch (error) {
    console.error(error)
}

First, we let the browser try to execute the document.querySelector() method with the selector we want to test. In case the selector is invalid, an exception is thrown and the code in the catch block is executed. In the example above, the error will then be output to the console.

We can now wrap this in a reusable function that returns true in case our selector is supported and false if is isn’t:

const isSelectorSupported = (selector) => {
    try {
        document.querySelector(selector)
        return true
    } catch (error) {
        return false
    }
}

Now, you can test for support of any selector and, for example, add a class to the element, if a browser “cuts the mustard.”

if (isSelectorSupported(":where(body)")) {
    document.documentElement.classList.add("supports-where")
}

I’d still recommend you use a CSS-only solution to check for support whenever possible. But for all other cases, this little helper function might prove very useful.

✍️✍️✍️ Edit #

Shortly after I shared this post on Twitter, I received two replies by Mehdi Merah and Bramus van Damme, who both suggested alternative methods of detecting support for a selector. First of all: thanks a lot! 🤗 Let's have a look at them.

Using CSS Custom Properties to check for selector support #

Mehdi mentioned that one could also use CSS Custom Properties to emulate @supports in JavaScript. A smart solution and one that can be combined with your existing rules. The idea is that you first define a custom property that basically acts as a boolean variable and then set it to a different value inside of the selector you want to test support for:

:root {
  --supports-selector-where: 0;
  
  @supports selector(:where(a)) {
    --supports-selector-where: 1;
  }
}

In our case, we can even reduce it further and only set the custom property using a selector with :where(). If the browser supports it, it will set the custom property to 1:

:where(:root) {
  --supports-selector-where: 1;
}

In JavaScript, we can now access the value of our custom property with getComputedStyle and getPropertyValue. And if the value is 1, we know that the selector is supported.

const rootStyles = getComputedStyle(document.documentElement)
const supportsSelectorWhere = rootStyles.getPropertyValue('--supports-selector-where').trim() == "1"

console.log(supportsSelectorWhere) // boolean -> true if supported

This technique can not only be used to detect support for selectors but for any other cases where you want to communicate a status from CSS back to JavaScript. Andy Bell wrote a brilliant little helper function that even lets you state which datatype you want to get back:

/**
 * Pass in an element and its CSS Custom Property that you want the value of.
 * Optionally, you can determine what datatype you get back.
 *
 * @param {String} propKey
 * @param {HTMLELement} element=document.documentElement
 * @param {String} castAs='string'
 * @returns {*}
 */
const getCSSCustomProp = (propKey, element = document.documentElement, castAs = 'string') => {
  let response = getComputedStyle(element).getPropertyValue(propKey);

  // Tidy up the string if there's something to work with
  if (response.length) {
    response = response.replace(/\'|"/g, '').trim();
  }

  // Convert the response into a whatever type we wanted
  switch (castAs) {
    case 'number':
    case 'int':
      return parseInt(response, 10);
    case 'float':
      return parseFloat(response, 10);
    case 'boolean':
    case 'bool':
      return response === 'true' || response === '1';
  }

  // Return the string response by default
  return response;
};

With this helper function, we can check for support for :where() with the custom property from before and one line of JS:

const isWhereSupported = getCSSCustomProp('--supports-selector-where', document.documentElement, 'boolean')

Using CSS.supports() #

Bramus suggested taking another route: the CSS.supports() method. This native JavaScript method with really good browser support accepts anything you may put inside a supports at-rule, so we can do this:

const supportsWhere = CSS.supports('selector(:where())');

if (supportsWhere) {
    document.documentElement.classList.add("supports-where");
}

And that’s it. Plain and simple.

Definitely my favorite solution because of good browser support and its simplicity – and something I probably wouldn’t have learned about if I hadn’t written and shared a blog post about my problem.

~