{"id":4121,"date":"2024-10-07T11:44:04","date_gmt":"2024-10-07T16:44:04","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=4121"},"modified":"2024-10-07T11:44:05","modified_gmt":"2024-10-07T16:44:05","slug":"reminder-that-scope-and-html-style-blocks-are-a-potent-combo","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/reminder-that-scope-and-html-style-blocks-are-a-potent-combo\/","title":{"rendered":"Reminder that @scope and HTML style blocks are a potent combo"},"content":{"rendered":"\n<p>There are <em>so many<\/em> different tools for writing scoped CSS with very different takes on how to go about it. Sometimes it&#8217;s only a sub-feature of a tool that does other things. But it&#8217;s generally thought of as a concept the requires tooling to accomplish.<\/p>\n\n\n\n<p>Have you ever written a React component that imported scoped styles, perhaps as a CSS module?<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> styles <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/MyComponent.module.css\"<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Or used a Styled Component to push some styles onto a component you&#8217;re already defining?<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> Button = styled.button<span class=\"hljs-string\">``<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Maybe your Vue components used <code>&lt;style scoped&gt;<\/code> blocks within them like you can do with Vue Single File Components out of the box? <\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span>&gt;<\/span>Submit<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span> <span class=\"hljs-attr\">scoped<\/span>&gt;<\/span><span class=\"xml\">\n  button {\n    border: 3px solid green;\n  }\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Despite the seemingly widely-applicable <code>button<\/code> selector above, the styles will actually be tightly scoped to the button you see in the template after processing.<\/p>\n\n\n\n<p>Or maybe you use Tailwind to apply styling classes directly to elements and like it partially because you don&#8217;t have to &#8220;name anything&#8221;.<\/p>\n\n\n\n<p>There are <em>a lot<\/em> of solutions like this out there in the land of building websites. <strong>I&#8217;m pretty convinced myself that scoped CSS is a good idea:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>There is little to worry about. Styles won&#8217;t leak out and have unintended consequences.<\/li>\n\n\n\n<li>It&#8217;s possible to do efficient things like not load the styles for components that don&#8217;t appear on a particular page at the time of loading.<\/li>\n\n\n\n<li>When a component retires, so do it&#8217;s styles.<\/li>\n\n\n\n<li>Styles are often &#8220;co-located&#8221; with the component, meaning there is a logical obvious connection between markup and styles.<\/li>\n<\/ul>\n\n\n\n<p><strong>I&#8217;m here to tell you: you can do all this stuff with just HTML and CSS.<\/strong><\/p>\n\n\n\n<p>And I&#8217;m not even talking about Web Components or anything particularly controversial or limiting. Vanilla HTML and CSS. <\/p>\n\n\n\n<p>What you do is dump a <code>&lt;style&gt;<\/code> block in the HTML at the point you want the styles scoped. Just like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n\n   <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n     <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Dum de dum de dum.<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n   <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n   <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n     <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>Hi ho here we go.<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\n     <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span>&gt;<\/span><span class=\"xml\">\n      @scope { \/* Scope is the <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span> above, as this is a direct child. *\/\n        :scope { \/* This selects the <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span> *\/\n          border: 1px solid red;\n          \n          \/* I can use CSS nesting in here, ensuring *everything* is safely scoped *\/\n          p {\n            color: red;\n          }\n        }\n      }\n     <\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span>\n   <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Here&#8217;s an example of using it where one of these three <code>&lt;article&gt;<\/code>s has a scoped styles variation:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_poMbRmG\" src=\"\/\/codepen.io\/anon\/embed\/poMbRmG?height=450&amp;theme-id=47434&amp;slug-hash=poMbRmG&amp;default-tab=html,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed poMbRmG\" title=\"CodePen Embed poMbRmG\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>I&#8217;m using the scoped styles as a &#8220;variation&#8221; there, but the whole block of styles of that component could be used like that whether it is a variation or not. It&#8217;s a way to apply styling <em>only<\/em> to a particular branch of the ol&#8217; DOM tree. No tooling required. Any way you produce components that end up in the DOM could be done this way, from basic HTML includes to fancy framework components. <\/p>\n\n\n\n<p>Why isn&#8217;t this being used much?<\/p>\n\n\n\n<p>Well, it&#8217;s the Firefox support mostly I think. Firefox just straight up doesn&#8217;t <a href=\"https:\/\/caniuse.com\/css-cascade-scope\">support it<\/a> at the time of this writing. I&#8217;d say this is a strong candidate for Interop 2025. It looked like it was tried for in 2024 but maybe it was too new or something. But maybe Interop isn&#8217;t needed as it appears as if it&#8217;s being <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1830512\">actively worked on<\/a>, so maybe it won&#8217;t be long, dunno.<\/p>\n\n\n\n<p>Once Firebox support is there, I could imagine this as being highly used as a way to accomplish scoped styles for components. It doesn&#8217;t require <em>any<\/em> tooling or have <em>any<\/em> limitations on what CSS you can use. I would think that would appeal to any existing CSS scoping tool as it would require them to do much less work and work faster. <\/p>\n\n\n\n<p><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/@scope\">CSS @scope<\/a> can do more things, but this particular feature is my favorite and likely to have the biggest impact over time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There is an entirely web-platform way of injecting scoped CSS styles into the DOM. It&#8217;s requires zero tooling. Will we see it being used more, once Firebox support is there?<\/p>\n","protected":false},"author":1,"featured_media":4123,"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":""},"categories":[1],"tags":[243,7],"class_list":["post-4121","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-scope","tag-css"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/10\/pexels-photo-21716096.jpeg?fit=1880%2C1253&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4121","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=4121"}],"version-history":[{"count":2,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4121\/revisions"}],"predecessor-version":[{"id":4124,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4121\/revisions\/4124"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/4123"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=4121"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=4121"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=4121"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}