{"id":7741,"date":"2025-11-13T14:56:46","date_gmt":"2025-11-13T19:56:46","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=7741"},"modified":"2025-11-13T14:56:47","modified_gmt":"2025-11-13T19:56:47","slug":"browserslist-baseline","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/browserslist-baseline\/","title":{"rendered":"Browserslist &amp; Baseline"},"content":{"rendered":"\n<p>I saw Tony Conway &amp; <a href=\"https:\/\/github.com\/tonypconway\"><\/a><a href=\"https:\/\/www.linkedin.com\/in\/tonypconway\"><\/a>Jeremy Wagner&#8217;s post on web.dev, <a href=\"https:\/\/web.dev\/articles\/use-baseline-with-browserslist?hl=en\">Use Baseline with Browserslist<\/a>, and I had a little play with it myself (<a href=\"https:\/\/www.youtube.com\/live\/PAT1cCA9kYw\">saved live stream<\/a>). Allow me to write down what I know and what I learned.<\/p>\n\n\n\n<p>So here&#8217;s <a href=\"https:\/\/browsersl.ist\/\">Browserslist<\/a><sup data-fn=\"8ff103a5-0fda-4d35-bac1-750c7c7818d2\" class=\"fn\"><a href=\"#8ff103a5-0fda-4d35-bac1-750c7c7818d2\" id=\"8ff103a5-0fda-4d35-bac1-750c7c7818d2-link\">1<\/a><\/sup>.<\/p>\n\n\n\n<p>Browserslist is the developer community at it&#8217;s best. There are a bunch of tools that make choices about what they do based on what browsers they are trying to support. Like the intro on their homepage says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Shared browser compatibility config for popular JavaScript tools like&nbsp;<a href=\"https:\/\/github.com\/postcss\/autoprefixer?tab=readme-ov-file#browsers\">Autoprefixer \/ PostCSS<\/a>, <a href=\"https:\/\/babeljs.io\/docs\/babel-preset-env#browserslist-integration\">Babel<\/a>, <a href=\"https:\/\/github.com\/amilajack\/eslint-plugin-compat?tab=readme-ov-file#3-configure-target-browsers\">ESLint<\/a>, and <a href=\"https:\/\/webpack.js.org\/configuration\/target\/\">Webpack<\/a><\/p>\n<\/blockquote>\n\n\n\n<p>Links to those tools added by me, linking to their Browserslist details. <a href=\"https:\/\/lightningcss.dev\/\">LightningCSS<\/a> is another one.<\/p>\n\n\n\n<p>So instead of all these tools coming up with their own syntax for how to express a set of supported browsers, they all use this <em>shared<\/em> syntax. And not even just a shared syntax, they can even share the same location or file (i.e. <code>.browserslist<\/code>) to store that information. <\/p>\n\n\n\n<p>That&#8217;s great. It&#8217;s in the same vein as the famed <code><a href=\"https:\/\/docs.npmjs.com\/cli\/v11\/configuring-npm\/package-json\">package.json<\/a><\/code> file being the canonical source of packages and JavaScript processing information, or <code><a href=\"https:\/\/editorconfig.org\/\">.editorconfig<\/a><\/code> for all editor behavior and prettification needs.<\/p>\n\n\n\n<p>Browserslist recommends <code>\"defaults\"<\/code> if &#8220;you\u2019re building a&nbsp;web&nbsp;application for the&nbsp;global audience.&#8221; This translates to their config <code>\"&gt; 0.5%, last 2 versions, Firefox ESR, not dead\"<\/code>. That translates to any browser which has more than half a percent of browser share (it gets browser data <a href=\"https:\/\/github.com\/browserslist\/update-db\/blob\/main\/index.js\">like this<\/a>), the last two major versions of all major browsers, Firefox &#8220;Extended Support Release&#8221; specifically, and only &#8220;not dead&#8221; browsers (as in, not Internet Explorer). <\/p>\n\n\n\n<p>That&#8217;s pretty reasonable? But you can always add things to your support list if you need to go deeper or be more specific.<\/p>\n\n\n\n<p>But now Google is in the game of qualifiying web platform features with <a href=\"https:\/\/web.dev\/baseline\">Baseline<\/a>.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Web Platform Baseline brings clarity to information about browser support for web platform features.<\/p>\n<\/blockquote>\n\n\n\n<p>Their biggest rubber stamps are &#8220;widely available&#8221; and &#8220;newly available&#8221;. <\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<ul class=\"wp-block-list\">\n<li><strong>Baseline Widely available<\/strong>&nbsp;includes all web features that were fully supported by the Baseline core browser set 30 or more months in the past.<\/li>\n\n\n\n<li>Baseline year feature sets, for example&nbsp;<strong>Baseline 2020<\/strong>, include all features that were&nbsp;<strong>Newly available<\/strong>&nbsp;at the end of the specified year.<\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<p>This means you can literally use Browserslist config strings to use these delegations. <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">\"baseline newly available\"<br>\"baseline widely available\"<br>\"baseline 2022\"<\/pre>\n\n\n\n<p>Specifying a year, like the last example above, might be how your project wants to roll! I don&#8217;t hate it, honestly. If I were to use <code>\"baseline 2020\"<\/code> as config and run CSS through Lightning CSS, I&#8217;d see some transformations like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"595\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.22.50%402x.png?resize=1024%2C595&#038;ssl=1\" alt=\"\" class=\"wp-image-7750\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.22.50%402x.png?resize=1024%2C595&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.22.50%402x.png?resize=300%2C174&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.22.50%402x.png?resize=768%2C446&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.22.50%402x.png?resize=1536%2C892&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.22.50%402x.png?w=1860&amp;ssl=1 1860w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-element-caption\"><code>oklch()<\/code> not supported at all, so transformed into three different formats, supporting as much as it can. <code>light-dark()<\/code> not supported at all, so provides custom properties for your own implementation, and <code>mask<\/code> is vendor prefixed.<\/figcaption><\/figure>\n\n\n\n<p>If we went back to <code>\"baseline 2018\"<\/code> we&#8217;d even see some big transformations of <code>padding-inline-start<\/code> transformed into <code>padding-left<\/code> for a big ol&#8217; pile of <code>:lang()<\/code> values and <code>padding-right<\/code> for another big pile (!!).<\/p>\n\n\n\n<p>If we went forward to <code>\"baseline 2022\"<\/code> we&#8217;d see the <code>color()<\/code> declaration go away, leaving only the #hex and <code>lab()<\/code> values left, but the rest would be the same.<\/p>\n\n\n\n<p>I think the general &#8220;recommendation&#8221; (if that&#8217;s fair) is to use <code>\"baseline widely available\"<\/code> where our CSS transformations are like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"545\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.29.33%402x.png?resize=1024%2C545&#038;ssl=1\" alt=\"\" class=\"wp-image-7751\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.29.33%402x.png?resize=1024%2C545&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.29.33%402x.png?resize=300%2C160&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.29.33%402x.png?resize=768%2C409&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.29.33%402x.png?resize=1536%2C818&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.29.33%402x.png?w=1856&amp;ssl=1 1856w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-element-caption\">The <code>oklch()<\/code> color is left alone, but we still see the <code>light-dark()<\/code> transformation and the vendor prefixing for <code>mask<\/code>. <\/figcaption><\/figure>\n\n\n\n<p>Using <code>\"baseline newly available\"<\/code> is <em>still somewhat cross-browser compatible<\/em>, just not to the level of widely available. <strong>To be &#8220;widely&#8221; available the feature needs to be baseline for 30 months! <\/strong>So I&#8217;d say pretty-darn available. Using <code>\"baseline newly available\"<\/code> we get:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"361\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.32.47%402x.png?resize=1024%2C361&#038;ssl=1\" alt=\"\" class=\"wp-image-7752\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.32.47%402x.png?resize=1024%2C361&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.32.47%402x.png?resize=300%2C106&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.32.47%402x.png?resize=768%2C271&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.32.47%402x.png?resize=1536%2C542&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/CleanShot-2025-11-12-at-15.32.47%402x.png?resize=2048%2C723&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><figcaption class=\"wp-element-caption\">Just some trivial conversion of colors, which is mostly a minification thing.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Example Repo<\/h2>\n\n\n\n<p><a href=\"https:\/\/css-tricks.com\/compiling-css-with-vite-and-lightning-css\/\">I tossed together a repo<\/a> for testing this stuff. You can basically <a href=\"https:\/\/github.com\/chriscoyier\/baseline-browserslist\/blob\/main\/vite-project\/vite.config.mjs#L9-L13\">change the config here<\/a>. It&#8217;s an <code>npm run dev<\/code> thing and it&#8217;s wired up to not fingerprint or minify, so it&#8217;s easy to see both <code>src<\/code> and <code>dist<\/code> files like the screenshots I was doing above.<\/p>\n\n\n\n<p>It&#8217;s also wired up to do JavaScript processing with Babel, although I&#8217;m not 100% sure I even did that part right, but if you wanted to test JavaScript transformation on this stuff, it might be a good starting point.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Stuff That Isn&#8217;t Touched<\/h2>\n\n\n\n<p>Remember that CSS features aren&#8217;t always transformable to backwards-compatible things. Like if you use <code>@layer<\/code> or <code>rlh<\/code> units or something, that&#8217;s just going to get left alone despite any browser support levels. Same with stuff like <code>shape()<\/code>, which <a href=\"https:\/\/frontendmasters.com\/blog\/shape-a-new-powerful-drawing-syntax-in-css\/\">is brand new<\/a>, and would be awesome if they ported it to something, but alas, they do not.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Final Thoughts<\/h2>\n\n\n\n<p>I think it comes down to a battle: <code>\"defaults\"<\/code> vs. <code>\"baseline widely available\"<\/code>. Anything else is just playing around or very specialty situations. Between the two, I think I&#8217;d actually go with <code>\"baseline widely available\"<\/code>. It just seems a <em>smidge<\/em> more modern and I like the momentum behind it. <\/p>\n\n\n\n<p>The <em>best<\/em> possible move is to use your own analytics data to inform the choices. This can be done with a Baseline Target Report and Jeremy Wagner and Rachel Andrew get into it in <a href=\"https:\/\/web.dev\/articles\/how-to-choose-your-baseline-target?hl=en\">How to choose your Baseline target<\/a>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n<ol class=\"wp-block-footnotes\"><li id=\"8ff103a5-0fda-4d35-bac1-750c7c7818d2\">The pluralization of Browserslist is weird. Feels like it should be Browserlist. You&#8217;ll also see config strings like &#8220;last 2 version&#8221; which then <em>lacks<\/em> the pluralization it wants (but it also works pluralized). \ud83e\udd37\u200d\u2640\ufe0f <a href=\"#8ff103a5-0fda-4d35-bac1-750c7c7818d2-link\" aria-label=\"Jump to footnote reference 1\">\u21a9\ufe0e<\/a><\/li><\/ol>\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I saw Tony Conway &amp; Jeremy Wagner&#8217;s post on web.dev, Use Baseline with Browserslist, and I had a little play with it myself (saved live stream). Allow me to write down what I know and what I learned. So here&#8217;s Browserslist. Browserslist is the developer community at it&#8217;s best. There are a bunch of tools [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":7756,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"[{\"content\":\"The pluralization of Browserslist is weird. Feels like it should be Browserlist. You'll also see config strings like \\\"last 2 version\\\" which then <em>lacks<\/em> the pluralization it wants (but it also works pluralized). \ud83e\udd37\u200d\u2640\ufe0f\",\"id\":\"8ff103a5-0fda-4d35-bac1-750c7c7818d2\"}]"},"categories":[1],"tags":[423,73,422,33],"class_list":["post-7741","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-analytics","tag-baseline","tag-browserslist","tag-lightning-css"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/11\/baseline-browserslist.jpg?fit=2000%2C1200&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/7741","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=7741"}],"version-history":[{"count":7,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/7741\/revisions"}],"predecessor-version":[{"id":7757,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/7741\/revisions\/7757"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/7756"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=7741"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=7741"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=7741"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}