{"rowid": 64, "title": "Being Responsive to the Small Things", "contents": "It\u2019s that time of the year again to trim the tree with decorations. Or maybe a DOM tree?\nAny web page is made of HTML elements that lay themselves out in a tree structure. We start at the top and then have multiple branches with branches that branch out from there. \n\nTo decorate our tree, we use CSS to specify which branches should receive the tinsel we wish to adorn upon it. It\u2019s all so lovely.\nIn years past, this was rather straightforward. But these days, our trees need to be versatile. They need to be responsive!\nResponsive web design is pretty wonderful, isn\u2019t it? Based on our viewport, we can decide how elements on the page should change their appearance to accommodate various constraints using media queries.\nClearleft have a delightfully clean and responsive site\nAlas, it\u2019s not all sunshine, lollipops, and rainbows. \nWith complex layouts, we may have design chunks \u2014 let\u2019s call them components \u2014 that appear in different contexts. Each context may end up providing its own constraints on the design, both in its default state and in its possibly various responsive states.\n\nMedia queries, however, limit us to the context of the entire viewport, not individual containers on the page. For every container our component lives in, we need to specify how to rearrange things in that context. The more complex the system, the more contexts we need to write code for.\n@media (min-width: 800px) {\n .features > .component { }\n .sidebar > .component {}\n .grid > .component {}\n}\nEach new component and each new breakpoint just makes the entire system that much more difficult to maintain. \n@media (min-width: 600px) {\n .features > .component { }\n .grid > .component {}\n}\n\n@media (min-width: 800px) {\n .features > .component { }\n .sidebar > .component {}\n .grid > .component {}\n}\n\n@media (min-width: 1024px) {\n .features > .component { }\n}\nEnter container queries\nContainer queries, also known as element queries, allow you to specify conditional CSS based on the width (or maybe height) of the container that an element lives in. In doing so, you no longer have to consider the entire page and the interplay of all the elements within. \nWith container queries, you\u2019ll be able to consider the breakpoints of just the component you\u2019re designing. As a result, you end up specifying less code and the components you develop have fewer dependencies on the things around them. (I guess that makes your components more independent.)\nAwesome, right?\nThere\u2019s only one catch.\nBrowsers can\u2019t do container queries. There\u2019s not even an official specification for them yet. The Responsive Issues (n\u00e9e Images) Community Group is looking into solving how such a thing would actually work. \nSee, container queries are tricky from an implementation perspective. The contents of a container can affect the size of the container. Because of this, you end up with troublesome circular references. \nFor example, if the width of the container is under 500px then the width of the child element should be 600px, and if the width of the container is over 500px then the width of the child element should be 400px. \nCan you see the dilemma? When the container is under 500px, the child element resizes to 600px and suddenly the container is 600px. If the container is 600px, then the child element is 400px! And so on, forever. This is bad.\nI guess we should all just go home and sulk about how we just got a pile of socks when we really wanted the Millennium Falcon. \nOur saviour this Christmas: JavaScript\nThe three wise men \u2014 Tim Berners-Lee, H\u00e5kon Wium Lie, and Brendan Eich \u2014 brought us the gifts of HTML, CSS, and JavaScript. \nTo date, there are a handful of open source solutions to fill the gap until a browser implementation sees the light of day.\n\nElementary by Scott Jehl\nElementQuery by Tyson Matanich\nEQ.js by Sam Richards\nCSS Element Queries from Marcj\n\nUsing any of these can sometimes feel like your toy broke within ten minutes of unwrapping it.\nEach take their own approach on how to specify the query conditions. For example, Elementary, the smallest of the group, only supports min-width declarations made in a :before selector.\n.mod-foo:before {\n content: \u201c300 410 500\u201d;\n}\nThe script loops through all the elements that you specify, reading the content property and then setting an attribute value on the HTML element, allowing you to use CSS to style that condition. \n.mod-foo[data-minwidth~=\"300\"] {\n background: blue;\n}\nTo get the script to run, you\u2019ll need to set up event handlers for when the page loads and for when it resizes. \nwindow.addEventListener( \"load\", window.elementary, false );\nwindow.addEventListener( \"resize\", window.elementary, false );\nThis works okay for static sites but breaks down on pages where elements can expand or contract, or where new content is dynamically inserted.\nIn the case of EQ.js, the implementation requires the creation of the breakpoints in the HTML. That means that you have implementation details in HTML, JavaScript, and CSS. (Although, with the JavaScript, once it\u2019s in the build system, it shouldn\u2019t ever be much of a concern unless you\u2019re tracking down a bug.)\nAnother problem you may run into is the use of content delivery networks (CDNs) or cross-origin security issues. The ElementQuery and CSS Element Queries libraries need to be able to read the CSS file. If you are unable to set up proper cross-origin resource sharing (CORS) headers, these libraries won\u2019t help.\nAt Shopify, for example, we had all of these problems. The admin that store owners use is very dynamic and the CSS and JavaScript were being loaded from a CDN that prevented the JavaScript from reading the CSS. \nTo go responsive, the team built their own solution \u2014 one similar to the other scripts above, in that it loops through elements and adds or removes classes (instead of data attributes) based on minimum or maximum width.\nThe caveat to this particular approach is that the declaration of breakpoints had to be done in JavaScript. \n elements = [\n { \u2018module\u2019: \u201c.carousel\u201d, \u201cclassName\u201d:\u2019alpha\u2019, minWidth: 768, maxWidth: 1024 },\n { \u2018module\u2019: \u201c.button\u201d, \u201cclassName\u201d:\u2019beta\u2019, minWidth: 768, maxWidth: 1024 } ,\n { \u2018module\u2019: \u201c.grid\u201d, \u201cclassName\u201d:\u2019cappa\u2019, minWidth: 768, maxWidth: 1024 }\n ]\nWith that done, the script then had to be set to run during various events such as inserting new content via Ajax calls. This sometimes reveals itself in flashes of unstyled breakpoints (FOUB). An unfortunate side effect but one largely imperceptible.\nUsing this approach, however, allowed the Shopify team to make the admin responsive really quickly. Each member of the team was able to tackle the responsive story for a particular component without much concern for how all the other components would react. \n\nEach element responds to its own breakpoint that would amount to dozens of breakpoints using traditional breakpoints. This approach allows for a truly fluid and adaptive interface for all screens.\nChristmas is over\nI wish I were the bearer of greater tidings and cheer. It\u2019s not all bad, though. We may one day see browsers implement container queries natively. At which point, we shall all rejoice!", "year": "2015", "author": "Jonathan Snook", "author_slug": "jonathansnook", "published": "2015-12-19T00:00:00+00:00", "url": "https://24ways.org/2015/being-responsive-to-the-small-things/", "topic": "code"}