{"rowid": 201, "title": "Lint the Web Forward With Sonarwhal", "contents": "Years ago, when I was in a senior in college, much of my web development courses focused on two things: the basics like HTML and CSS (and boy, do I mean basic), and Adobe Flash. I spent many nights writing ActionScript 3.0 to build interactions for the websites that I would add to my portfolio. A few months after graduating, I built one website in Flash for a client, then never again. Flash was dying, and it became obsolete in my r\u00e9sum\u00e9 and portfolio. \nThat was my first lesson in the speed at which things change in technology, and what a daunting realization that was as a new graduate looking to enter the professional world. Now, seven years later, I work on the Microsoft Edge team where I help design and build a tool that would have lessened my early career anxieties: sonarwhal. \nSonarwhal is a linting tool, built by and for the web community. The code is open source and lives under the JS Foundation. It helps web developers and designers like me keep up with the constant change in technology while simultaneously teaching how to code better websites. \nIntroducing sonarwhal\u2019s mascot Nellie\nGood web development is hard. It is more than HTML, CSS, and JavaScript: developers are expected to have a grasp of accessibility, performance, security, emerging standards, and more, all while refreshing this knowledge every few months as the web evolves. It\u2019s a lot to keep track of.\n\u00a0\nWeb development is hard \nStaying up-to-date on all this knowledge is one of the driving forces for developing this scanning tool. Whether you are just starting out, are a student, or you have over a decade of experience, the sonarwhal team wants to help you build better websites for all browsers. \nCurrently sonarwhal checks for best practices in five categories: Accessibility, Interoperability, Performance, PWAs, and Security. Each check is called a \u201crule\u201d. You can configure them and even create your own rules if you need to follow some specific guidelines for your project (e.g. validate analytics attributes, title format of pages, etc.). \nYou can use sonarwhal in two ways:\n\nAn online version, that provides a quick and easy way to scan any public website.\nA command line tool, if you want more control over the configuration, or want to integrate it into your development flow.\n\nThe Online Scanner\nThe online version offers a streamlined way to scan a website; just enter a URL and you will get a web page of scan results with a permalink that you can share and revisit at any time.\nThe online version of sonarwal\nWhen my team works on a new rule, we spend the bulk of our time carefully researching each subject, finding sources, and documenting it rather than writing the rule\u2019s code. Not only is it important that we get you the right results, but we also want you to understand why something is failing. Next to each failing rule you\u2019ll find a link to its detailed documentation, explaining why you should care about it, what exactly we are testing, examples that pass and examples that don\u2019t, and useful links to even more in-depth documentation if you are interested in the subject.\nWe hope that between reading the documentation and continued use of sonarwhal, developers can stay on top of best practices. As devs continue to build sites and identify recurring issues that appear in their results, they will hopefully start to automatically include those missing elements or fix those pieces of code that are producing errors. This also isn\u2019t a one-way communication: the documentation is not only available on the sonarwhal site, but also on GitHub for editing so you can help us make it even better!\nA results report\nThe current configuration for the online scanner is very strict, so it might hurt your feelings (it did when I first tested it on my personal website). But you can configure sonarwhal to any level of strictness as well as customize the command line tool to your needs! \nSonarwhal\u2019s CLI\u00a0\nThe CLI gives you full control of sonarwhal: what rules to use, tweaks to them, domains that are out of your control, and so on. You will need the latest node LTS (v8) or Stable (v9) and your favorite package manager, such as npm:\nnpm install -g sonarwhal\nYou can now run sonarwhal from anywhere via:\nsonarwhal https://example.com\nUsing the CLI\nThe configuration is done via a .sonarwhalrc file. When analyzing a site, if no file is available, you will be prompted to answer a series of questions:\n\nWhat connector do you want to use? Connectors are what sonarwhal uses to access a website and gather all the information about the requests, resources, HTML, etc. Currently it supports jsdom, Microsoft Edge, and Google Chrome.\nWhat formatter? This is how you want to see the results: summary, stylish, etc. Make sure to look at the full list. Some are concise for, perfect for a quick build assessment, while others are more verbose and informative.\nDo you want to use the recommended rules configuration? Rules are the things we are validating. Unless you\u2019ve read the documentation and know what you are doing, first timers should probably use the recommended configuration.\nWhat browsers are you targeting? One of the best features of sonarwhal is that rules can adapt their feedback depending on your targeted browsers, suggesting to add or remove things. For example, the rule \u201cHighest Document Mode\u201d will tell you to add the \u201cX-UA-Compatible\u201d header if IE10 or lower is targeted or remove if the opposite is true. \n\nsonarwhal configuration generator questions\nOnce you answer all these questions the scan will start and you will have a .sonarwhalrc file similar to the following:\n{\n \"connector\": {\n \"name\": \"jsdom\",\n \"options\": {\n \"waitFor\": 1000\n }\n },\n \"formatters\": \"stylish\",\n \"rulesTimeout\": 120000,\n \"rules\": {\n \"apple-touch-icons\": \"error\",\n \"axe\": \"error\",\n \"content-type\": \"error\",\n \"disown-opener\": \"error\",\n \"highest-available-document-mode\": \"error\",\n \"validate-set-cookie-header\": \"warning\",\n // ...\n }\n}\nYou should see the scan initiate in the command line and within a few seconds the results should start to appear. Remember, the scan results will look different depending on which formatter you selected so try each one out to see which one you like best. \nsonarwhal results on my website and hurting my feelings \ud83d\udc94\nNow that you have a list of errors, you can get to work improving the site! Note though, that when you scan your website, it scans all the resources on that page and if you\u2019ve added something like analytics or fonts hosted elsewhere, you are unable to change those files. You can configure the CLI to ignore files from certain domains so that you are only getting results for files you are in control of.\nThe documentation should give enough guidance on how to fix the errors, but if it\u2019s insufficient, please help us and suggest edits or contribute back to it. This is a community effort and chances are someone else will have the same question as you.\nWhen I scanned both my websites, sonarwhal alerted me to not having an Apple Touch Icon. If I search on the web as opposed to using the sonarwhal documentation, the first top 3 results give me outdated information: I need to include many different icon sizes. I don\u2019t need to include all the different size icons that target different devices. Declaring one icon sized 180px x 180px will provide a large enough icon for devices and it will scale down as appropriate for people on older devices. \nThe information at the top of the search results isn\u2019t always the correct answer to an issue and we don\u2019t want you to have to search through outdated documentation. As sonarwhal\u2019s capabilities expand, the goal is for it to be the one stop shop for helping preflight your website. \nThe journey up until now and looking forward\n\nOn the Microsoft Edge team, we\u2019re passionate about empowering developers to build great websites. Every day we see so many sites come through our issue tracker. (Thanks for filing those bugs, they help us make Microsoft Edge better and better!) Some issues we see over and over are honest mistakes or outdated \u2018best practices\u2019 that could be avoided, so we built this tool to help everyone help make the web a better place.\nWhen we decided to create sonarwhal, we wanted to create a tool that would help developers write better and more up-to-date code for their websites. We want sonarwhal to be useful to anyone so, early on, we defined three guiding principles we\u2019ve used along the way:\n\nCommunity Driven. We build for the community\u2019s best interests. The web belongs to everyone and this project should too. Not only is it open source, we\u2019ve also donated it to the JS Foundation and have an inclusive governance model that welcomes the collaboration of anyone, individual or company.\nUser Centric. We want to put the user at the center, making sonarwhal configurable for your needs and easy to use no matter what your skill level is.\nCollaborative. We didn\u2019t want to reinvent the wheel, so we collaborated with existing tools and services that help developers build for the web. Some examples are aXe, snyk.io, Cloudinary, etc.\n\nThis is just the beginning and we still have lots to do. We\u2019re hard at work on a backlog of exciting features for future releases, such as:\n\nNew rules for a variety of areas like\u00a0performance,\u00a0accessibility,\u00a0security,\u00a0progressive web apps, and more.\nA plug-in for Visual Studio Code: we want sonarwhal to help you write better websites, and what better moment than when you are in your editor.\nConfiguration options for the online service: as we fine tune the infrastructure, the rule configuration for our scanner is locked, but we look forward to adding CLI customization options here in the near future.\n\nThis is a tool for the web community by the web community so if you are excited about sonarwhal, making a better web, and want to contribute, we have a\u00a0few issues where you might be able to help. Also, don\u2019t forget to check the rest of the\u00a0sonarwhal GitHub organization. PRs are always welcome and appreciated! \nLet us know what you think about the scanner at @NarwhalNellie on Twitter and we hope you\u2019ll help us lint the web forward!", "year": "2017", "author": "Stephanie Drescher", "author_slug": "stephaniedrescher", "published": "2017-12-02T00:00:00+00:00", "url": "https://24ways.org/2017/lint-the-web-forward-with-sonarwhal/", "topic": "code"} {"rowid": 202, "title": "Design Systems and CSS Grid", "contents": "Recently, my client has been looking at creating a few new marketing pages for their website. They currently have a design system in place but they\u2019re looking to push this forward into 2018 with some small and possibly some larger changes.\nTo start with we are creating a couple of new marketing pages. As well as making use of existing components within the design systems component library there are a couple of new components. Looking at the first couple of sketch files I felt this would be a great opportunity to use CSS Grid, to me the newer components need to be laid out on that page and grid would help with this perfectly.\n\nAs well as this layout of the new components and the text within it, imagery would be used that breaks out of the grid and pushes itself into the spaces where the text is aligned.\nThe existing grid system\nWhen the site was rebuilt in 2015 the team decided to make use of Sass and Susy, a \u201clightweight grid-layout engine using Sass\u201d. It was built separating the grid system from the components that would be laid out on the page with a container, a row, an optional column, and a block.\nTo make use of the grid system on a page for a component that would take the full width of the row you would have to write something like this:\n
\n
\n
\n
\n \n
\n
\n
\n
\nUsing a grid system similar to this can easily create quite the tag soup. It could fill the HTML full of divs that may become complex to understand and difficult to edit.\nAlthough there is this reliance on several
s to lay out the components on a page it does allow a tidy way to place the component code within that page. It abstracts the layout of the page to its own code, its own system, so the components can \u2018fit\u2019 where needed.\nThe requirements of the new grid system\nMoving forward I set myself some goals for what I\u2019d like to have achieved in this new grid system:\nIt needs to behave like the existing grid systems\nWe are not ripping up the existing grid system, it would be too much work, for now, to retrofit all of the existing components to work in a grid that has a different amount of columns, and spacing at various viewport widths.\nAllow full-width components\nCurrently the grid system is a 14 column grid that becomes centred on the page when viewport is wide enough. We have, in the past, written some CSS that would allow for a full-width component, but his had always felt like a hack. We want the option to have a full-width element as part of the new grid system, not something that needs CSS to fight against.\nLess of a tag soup\nIdeally we want to end up writing less HTML to layout the page. Although the existing system can be quite clear as to what each element is doing, it can also become a little laborious in working out what each grid row or block is doing where.\nI would like to move the layout logic to CSS as much as is possible, potentially creating some utility classes or additional \u2018layout classes\u2019 for the components.\nEasier for people to use and author\nWith many people using the existing design systems codebase we need to create a new grid system that is as easy or easier to use than the existing one. I think and hope this would be helped by removing as many
s as needed and would require new documentation and examples, and potentially some initial training.\nSeparating layout from style\nThere still needs to be a separation of layout from the styles for the component. To allow for the component itself to be placed wherever needed in the page we need to make sure that the CSS for the layout is a separate entity to the CSS for that styling.\nWith these base requirements I took to CodePen and started working on some throwaway code to get started.\nMaking the new grid(s)\nThe Full-Width Grid\nTo start with I created a grid that had three columns, one for the left, one for the middle, and one for the right. This would give the full-width option to components.\nThankfully, one of Rachel Andrew\u2019s many articles on Grid discussed this exact requirement of the new grid system to break out with Grid.\nI took some of the code in the examples and edited to make grid we needed.\n.container {\n display: grid;\n grid-template-columns:\n [full-start]\n minmax(.75em, 1fr)\n [main-start]\n minmax(0, 1008px)\n [main-end]\n minmax(.75em, 1fr)\n [full-end];\n}\nWe are declaring a grid, we have four grid column lines which we name and we define how the three columns they create react to the viewport width. We have a left and right column that have a minimum of 12px, and a central column with a maximum width of 1008px.\nBoth left and right columns fill up any additional space if the viewport is wider that 1032px wide. We are also not declaring any gutters to this grid, the left and right columns would act as gutters at smaller viewports.\nAt this point I noticed that older versions of Sass cannot parse the brackets in this code. To combat this I used Sass\u2019 unquote method to wrap around the value of the grid-template-column.\n.container {\n display: grid;\n grid-template-columns:\n unquote(\"\n [full-start]\n minmax(.75em, 1fr)\n [main-start]\n minmax(0, 1008px)\n [main-end]\n minmax(.75em, 1fr)\n [full-end]\n \");\n}\nThe existing codebase makes use of Sass variables, mixins and functions so to remove that would be a problem, but luckily the version of Sass used is up-to-date (note: example CodePens will be using CSS).\nThe initial full-width grid displays on a webpage as below:\n\nThe 14 column grid\nI decided to work out the 14 column grid as a separate prototype before working out how it would fit within the full-width grid. This grid is very similar to the 12 column grids that have been used in web design. Here we need 14 columns with a gutter between each one.\nAlong with the many other resources on Grid, Mozilla\u2019s MDN site had a page on common layouts using CSS Grid. This gave me the perfect CSS I needed to create my grid and I edited it as required:\n.inner {\n display: grid;\n grid-template-columns: repeat(14, [col-start] 1fr);\n grid-gap: .75em;\n}\nWe, again, are declaring a grid, and we are splitting up the available space by creating 14 columns with 1 fr-unit and giving each one a starting line named col-start.\nThis grid would display on web page as below:\n\nBringing the grids together\nNow that we have got the two grids we need to help fulfil our requirements we need to put them together so that they are actually we we need.\nThe subgrid\nThere is no subgrid in CSS, yet. To workaround this for the new grid system we could nest the 14 column grid inside the full-width grid.\nIn the HTML we nest the 14 column inner grid inside the full-width container.\n
\n
\n
\n
\nSo that the inner knows where to be laid out within the container we tell it what column to start and end with, with this code it would be the start and end of the main column.\n.inner {\n display: grid;\n grid-column: main-start / main-end;\n grid-template-columns: repeat(14, [col-start] 1fr);\n grid-gap: .75em;\n}\nThe CSS for the container remains unchanged.\n\nThis works, but we have added another div to our HTML. One of our requirements is to try and remove the potential for tag soup.\nThe faux subgrid subgrid\nI wanted to see if it would be possible to place the CSS for the 14 column grid within the CSS for the full-width grid. I replaced the CSS for the main grid and added the grid-column-gap to the .container.\n.container {\n display: grid;\n grid-gap: .75em;\n grid-template-columns:\n [full-start]\n minmax(.75em, 1fr)\n [main-start]\n repeat(14, [col-start] 1fr)\n [main-end]\n minmax(.75em, 1fr)\n [full-end];\n}\nWhat this gave me was a 16 column grid. I was unable to find a way to tell the main grid, the grid betwixt main-start and main-end to be a maximum of 1008px as required.\n\nI trawled the internet to find if it was possible to create our main requirement, a 14 column grid which also allows for full-width components. I found that we could not reverse minmax to minmax(1fr, 72px) as 1fr is not allowed as a minimum if there is a maximum. I tried working out if we could make the min larger than its max but in minmax it would be ignored.\nI was struggling, I was hoping for a cleaner version of the grid system we currently use but getting to the point where needing that extra
would be a necessity.\nAt 3 in the morning, when I was failing to get to sleep, my mind happened upon an question: \u201cCould you use calc?\u201d\nAt some point I drifted back to sleep so the next day I set upon seeing if this was possible. I knew that the maximum width of the central grid needed to be 1008px. The left and right columns needed to be however many pixels were left in the viewport divided by 2. In CSS it looked like I would need to use calc twice. The first time to takeaway 1008px from 100% of the viewport width and the second to divide that result by 2.\ncalc(calc(100% - 1008px) / 2)\nThe CSS above was part of the value that I would need to include in the declaration for the grid.\n.container {\n display: grid;\n grid-gap: .75em;\n grid-template-columns:\n [full-start]\n minmax(calc(calc(100% - 1008px) / 2), 1fr)\n [main-start]\n repeat(14, [col-start] 1fr)\n [main-end]\n minmax(calc(calc(100% - 1008px) / 2), 1fr)\n [full-end];\n}\nWe have created the grid required. A full-width grid, with a central 14 column grid, using fewer
elements.\n\nSee the Pen Design Systems and CSS Grid, 6 by Stuart Robson (@sturobson) on CodePen.\n\nSuccess!\nProgressive enhancement\nNow that we have created the grid system required we need to back-track a little.\nNot all browsers support Grid, over the last 9 months or so this has gotten a lot better. However there will still be browsers that visit that potentially won\u2019t have support. The effort required to make the grid system fall back for these browsers depends on your product or sites browser support.\n\nTo determine if we will be using Grid or not for a browser we will make use of feature queries. This would mean that any version of Internet Explorer will not get Grid, as well as some mobile browsers and older versions of other browsers.\n@supports (display: grid) {\n /* Styles for browsers that support Grid */\n}\nIf a browser does not pass the requirements for @supports we will fallback to using flexbox where possible, and if that is not supported we are happy for the page to be laid out in one column.\nA website doesn\u2019t have to look the same in every browser after all.\nA responsive grid\nWe started with the big picture, how the grid would be at a large viewport and the grid system we have created gets a little silly when the viewport gets smaller.\nAt smaller viewports we have a single column layout where every item of content, every component stacks atop each other. We don\u2019t start to define a grid before we the viewport gets to 700px wide. At this point we have an 8 column grid and if the viewport gets to 1100px or wider we have our 14 column grid.\n/*\n * to start with there is no 'grid' just a single column\n */\n.container {\n padding: 0 .75em;\n}\n\n/*\n * when we get to 700px we create an 8 column grid with\n * a left and right area to breakout of the grid.\n */\n@media (min-width: 700px) {\n .container {\n display: grid;\n grid-gap: .75em;\n grid-template-columns:\n [full-start]\n minmax(calc(calc(100% - 1008px) / 2), 1fr)\n [main-start]\n repeat(8, [col-start] 1fr)\n [main-end]\n minmax(calc(calc(100% - 1008px) / 2), 1fr)\n [full-end];\n padding: 0;\n }\n}\n\n/*\n * when we get to 1100px we create an 14 column grid with\n * a left and right area to breakout of the grid.\n */\n@media (min-width: 1100px) {\n .container {\n grid-template-columns:\n [full-start]\n minmax(calc(calc(100% - 1008px) / 2), 1fr)\n [main-start]\n repeat(14, [col-start] 1fr)\n [main-end]\n minmax(calc(calc(100% - 1008px) / 2), 1fr)\n [full-end];\n }\n}\nBeing explicit in creating this there is some repetition that we could avoid, we will define the number of columns for the inner grid by using a Sass variable or CSS custom properties (more commonly termed as CSS variables).\nLet\u2019s use CSS custom properties. We need to declare the variable first by adding it to our stylesheet.\n:root {\n --inner-grid-columns: 8;\n}\nWe then need to edit a few more lines. First make use of the variable for this line.\nrepeat(8, [col-start] 1fr)\n/* replace with */\nrepeat(var(--inner-grid-columns), [col-start] 1fr)\nThen at the 1100px breakpoint we would only need to change the value of the \u2014inner-grid-columns value.\n@media (min-width: 1100px) {\n .container {\n grid-template-columns:\n [full-start]\n minmax(calc(calc(100% - 1008px) / 2), 1fr)\n [main-start]\n repeat(14, [col-start] 1fr)\n [main-end]\n minmax(calc(calc(100% - 1008px) / 2), 1fr)\n [full-end];\n }\n}\n/* replace with */\n@media (min-width: 1100px) {\n .container {\n --inner-grid-columns: 14;\n }\n}\nSee the Pen Design Systems and CSS Grid, 8 by Stuart Robson (@sturobson) on CodePen.\n\nThe final grid system\nWe have finally created our new grid for the design system. It stays true to the existing grid in place, adds the ability to break-out of the grid, removes a
that could have been needed for the nested 14 column grid.\nWe can move on to the new component.\nCreating a new component\nBack to the new components we are needing to create.\n\nTo me there are two components one of which is a slight variant of the first. This component contains a title, subtitle, a paragraph (potentially paragraphs) of content, a list, and a call to action.\nTo start with we should write the HTML for the component, something like this:\n
\n

\n

\n
\n

\n
\n
    \n
  • \n
  • \n
\n \n
\nTo place the component on the existing grid is fine, but as child elements are not affected by the container grid we need to define another grid for the features component.\nAs the grid doesn\u2019t get invoked until 700px it is possible to negate the need for a media query.\n.features {\n grid-column: col-start 1 / span 6;\n}\n\n@supports (display: grid) {\n @media (min-width: 1100px) {\n .features {\n grid-column-end: 9;\n }\n }\n}\nWe can also avoid duplication of declarations by making use of the grid-column shorthand and longhand. We need to write a little more CSS for the variant component, the one that will sit on the right side of the page too.\n.features:nth-of-type(even) {\n grid-column-start: 4;\n grid-row: 2;\n}\n\n@supports (display: grid) {\n @media (min-width: 1100px) {\n .features:nth-of-type(even) {\n grid-column-start: 9;\n grid-column-end: 16;\n }\n }\n}\nWe cannot place the items within features on the container grid as they are not direct children. To make this work we have to define a grid for the features component.\nWe can do this by defining the grid at the first breakpoint of 700px making use of CSS custom properties again to define how many columns there will need to be.\n.features {\n grid-column: col-start 1 / span 6;\n --features-grid-columns: 5;\n}\n\n@supports (display: grid) {\n @media (min-width: 700px) {\n .features {\n display: grid;\n grid-gap: .75em;\n grid-template-columns: repeat(var(--features-grid-columns), [col-start] 1fr);\n }\n }\n}\n\n@supports (display: grid) {\n @media (min-width: 1100px) {\n .features {\n grid-column-end: 9;\n --features-grid-columns: 7;\n }\n }\n}\nSee the Pen Design Systems and CSS Grid, 10 by Stuart Robson (@sturobson) on CodePen.\n\nLaying out the parts\nLooking at the spec and reading several articles I feel there are two ways that I could layout the text of this component on the grid.\nWe could use the grid-column shorthand that incorporates grid-column-start and grid-column-end or we can make use of grid-template-areas.\ngrid-template-areas allow for a nice visual way of representing how the parts of the component would be laid out. We can take the the mock of the features on the grid and represent them in text in our CSS.\n\nWithin the .features rule we can add the relevant grid-template-areas value to represent the above.\n.features {\n display: grid;\n grid-template-columns: repeat(var(--features-grid-columns), [col-start] 1fr);\n grid-template-areas:\n \". title title title title title title\"\n \". subtitle subtitle subtitle subtitle subtitle . \"\n \". content content content content . . \"\n \". list list list . . . \"\n \". . . . link link link \";\n}\n\nIn order to make the variant of the component we would have to create the grid-template-areas for that component too.\nWe then need to tell each element of the component in what grid-area it should be placed within the grid.\n.features__title { grid-area: title; }\n.features__subtitle { grid-area: subtitle; }\n.features__content { grid-area: content; }\n.features__list { grid-area: list; }\n.features__link { grid-area: link; }\nSee the Pen Design Systems and CSS Grid, 12 by Stuart Robson (@sturobson) on CodePen.\n\nThe other way would be to use the grid-column shorthand and the grid-column-start and grid-column-end we have used previously.\n.features .features__title {\n grid-column: col-start 2 / span 6;\n}\n.features .features__subtitle {\n grid-column: col-start 2 / span 5;\n}\n.features .features__content {\n grid-column: col-start 2 / span 4;\n}\n.features .features__list {\n grid-column: col-start 2 / span 4;\n}\n.features .features__link {\n grid-column: col-start 5 / span 3;\n}\nFor the variant of the component we can use the grid-column-start property as it will inherit the span defined in the grid-column shorthand.\n.features:nth-of-type(even) .features__title {\n grid-column-start: col-start 1;\n}\n.features:nth-of-type(even) .features__subtitle {\n grid-column-start: col-start 1;\n}\n.features:nth-of-type(even) .features__content {\n grid-column-start: col-start 3;\n}\n.features:nth-of-type(even) .features__list {\n grid-column-start: col-start 3;\n}\n.features:nth-of-type(even) .features__link {\n grid-column-start: col-start 1;\n}\nSee the Pen Design Systems and CSS Grid, 14 by Stuart Robson (@sturobson) on CodePen.\n\nI think, for now, we will go with using grid-column properties rather than grid-template-areas. The repetition needed for creating the variant feels too much where we can change the grid-column-start instead, keeping the components elements layout properties tied a little closer to the elements rather than the grid.\nSome additional decisions\nThe current component library has existing styles for titles, subtitles, lists, paragraphs of text and calls to action. These are name-spaced so that they shouldn\u2019t clash with any other components. Looking forward there will be a chance that other products adopt the component library, but they may bring their own styles for titles, subtitles, etc.\nOne way that we could write our code now for that near future possibility is to make sure our classes are working hard. Using class-attribute selectors we can target part of the class attributes that we know the elements in the component will have using *=.\n.features [class*=\"title\"] {\n grid-column: col-start 2 / span 6;\n}\n.features [class*=\"subtitle\"] {\n grid-column: col-start 2 / span 5;\n}\n.features [class*=\"content\"] {\n grid-column: col-start 2 / span 4;\n}\n.features [class*=\"list\"] {\n grid-column: col-start 2 / span 4;\n}\n.features [class*=\"link\"] {\n grid-column: col-start 5 / span 3;\n}\nSee the Pen Design Systems and CSS Grid, 15 by Stuart Robson (@sturobson) on CodePen.\n\nAlthough the component we have created have a title, subtitle, paragraphs, a list, and a call to action there may be a time where one ore more of these is not required or available. One thing I found out is that if the element doesn\u2019t exist then grid will not create space for it. This may be obvious, but it can be really helpful in making a nice malleable component.\nWe have only looked at columns, as existing components have their own spacing for the vertical rhythm of the page we don\u2019t really want to have them take up equal space in the component and just take up the space as needed. We can do this by adding grid-auto-rows: min-content; to our .features. This is useful if you also need your component to take up a height that is more than the component itself.\nThe grid of the future\nFrom prototyping this new grid and components in CSS Grid, I\u2019ve found it a fantastic way to reimagine how we can create a layout or grid system for our sites. It gives us options to create the same layouts in differing ways that could suit a project and its needs.\nIt allows us to carry on \u2013 if we choose to \u2013 using a
-based grid but swapping out floats for CSS Grid or to tie it to our components so they have specific places to go depending on what component is being used. Or we could have several \u2018grid components\u2019 in our design system that we could use to layout various components throughout a page.\nIf you find yourself tasked with creating some new components for your design system try it. If you are starting from scratch I believe you really should start with CSS Grid for your layout.\nIt really feels like the possibilities are endless in terms of layout for the web.\nResources\nHere are just a few resources I have pawed over these last few weeks whilst getting acquainted with CSS Grid.\n\nA collection of CodePens from this article\nGrid by Example from Rachel Andrew\nA Complete Guide to CSS Grid on Codrops from Hui Jing Chen\nRachel Andrew\u2019s Blog Archive tagged: cssgrid\nCSS Grid Layout Examples\nMDN\u2019s CSS Grid Layout\nA Complete Guide to Grid from CSS-Tricks\nCSS Grid Layout Module Level 1 Specification", "year": "2017", "author": "Stuart Robson", "author_slug": "stuartrobson", "published": "2017-12-12T00:00:00+00:00", "url": "https://24ways.org/2017/design-systems-and-css-grid/", "topic": "code"} {"rowid": 204, "title": "Cascading Web Design with Feature Queries", "contents": "Feature queries, also known as the @supports rule, were introduced as an extension to the CSS2 as part of the CSS Conditional Rules Module Level 3, which was first published as a working draft in 2011. It is a conditional group rule that tests if the browser\u2019s user agent supports CSS property:value pairs, and arbitrary conjunctions (and), disjunctions (or), and negations (not) of them.\nThe motivation behind this feature was to allow authors to write styles using new features when they were supported but degrade gracefully in browsers where they are not. Even though the nature of CSS already allows for graceful degradation, for example, by ignoring unsupported properties or values without disrupting other styles in the stylesheet, sometimes we need a bit more than that.\nCSS is ultimately a holistic technology, in that, even though you can use properties in isolation, the full power of CSS shines through when used in combination. This is especially evident when it comes to building web layouts. Having native feature detection in CSS makes it much more convenient to build with cutting-edge CSS for the latest browsers while supporting older browsers at the same time.\nBrowser support\nOpera first implemented feature queries in November 2012, both Chrome and Firefox had it since May 2013. There have been several articles about feature queries written over the years, however, it seems that awareness of its broad support isn\u2019t that well-known. Much of the earlier coverage on feature queries was not written in English, and perhaps that was a limiting factor.\n\n@supports \u2015 CSS\u306eFeature Queries by Masataka Yakura, August 8 2012\nNative CSS Feature Detection via the @supports Rule by Chris Mills, December 21 2012\nCSS @supports by David Walsh, April 3 2013\nResponsive typography with CSS Feature Queries by Aral Balkan, April 9 2013\nHow to use the @supports rule in your CSS by Lea Verou, January 31 2014\nCSS Feature Queries by Amit Tal, June 2 2014\nComing Soon: CSS Feature Queries by Adobe Web Platform Team, August 21 2014\nCSS feature queries mittels @supports by Daniel Erlinger, November 27 2014\n\nAs of December 2017, all current major browsers and their previous 2 versions support feature queries. Feature queries are also supported on Opera Mini, UC Browser and Samsung Internet. The only browsers that do not support feature queries are Internet Explorer and Blackberry Mobile, but that may be less of an issue than you might think.\n\n Can I Use css-featurequeries? Data on support for the css-featurequeries feature across the major browsers from caniuse.com.\n\nGranted, there is still a significant number of organisations that require support of Internet Explorer. Microsoft still continues to support IE11 for the life-cycle of Windows 7, 8 and 10. They have, however, stopped supporting older versions since January 12, 2016. It is inevitable that there will be organisations that, for some reason or another, make it mandatory to support IE, but as time goes on, this number will continue to shrink.\nJen Simmons wrote an extensive article called Using Feature Queries in CSS which discussed a matrix of potential situations when it comes to the usage of feature queries. The following image is a summary of the aforementioned matrix.\n\nThe most tricky situation we have to deal with is the box in the top-left corner, which are \u201cbrowsers that don\u2019t support feature queries, yet do support the feature in question\u201d. For cases like those, it really depends on the specific CSS feature you want to use and a subsequent evaluation of the pros and cons of not including that feature in spite of the fact the browser (most likely Internet Explorer) supports it.\nThe basics of feature queries\nAs with any conditional, feature queries operate on boolean logic, in other words, if the query resolves to true, apply the CSS properties within the block, or else just ignore the entire block altogether. The syntax of a simple feature query is as follows:\n.selector {\n /* Styles that are supported in old browsers */\n}\n\n@supports (property:value) {\n .selector {\n /* Styles for browsers that support the specified property */\n }\n}\nNote that the parentheses around the property:value pair are mandatory and the rule is invalid without them. Styles that apply to older browsers, i.e. fallback styles, should come first, followed by the newer properties, which are contained within the @supports conditional. Because of the cascade, fallback styles will be overridden by the newer properties in the modern browsers that support them.\nmain {\n background-color: red;\n}\n\n@supports (display:grid) {\n main {\n background-color: green;\n }\n}\nIn this example, browsers that support CSS grid will have a main element with a green background colour because the conditional resolves to true, while browsers that do not support grid will have a main element with a red background colour.\nThe implication of such behaviour means that we can layer on enhanced styles based on the features we want to use and these styles will show up in browsers that support them. But for those that do not, they will get a more basic look that still works anyway. And that will be our approach moving forward.\nBoolean operators for feature queries\nThe and operator allows us to test for support of multiple properties within a single conditional. This would be useful for cases where the desired output requires multiple cutting-edge features to be supported at the same time to work. All the property:value pairs listed in the conditional must resolve to true for the styles within the rule to be applied.\n@supports (transform: rotate(45deg)) and\n (writing-mode: vertical-rl) {\n /* Some CSS styles */\n}\nThe or operator allows us to list multiple property:value pairs in the conditional and as long as one of them resolves to true, the styles within the block will be applied. A relevant use-case would be for properties with vendor-prefixes.\n@supports (background: -webkit-gradient(linear, left top, left bottom, from(white), to(black))) or\n (background: -o-linear-gradient(top, white, black)) or\n (background: linear-gradient(to bottom, white, black)) {\n /* Some CSS styles */\n}\nThe not operator negates the resolution of the property:value pair in the conditional, resolving to false when the property is supported and vice versa. This is useful when there are two distinct sets of styles to be applied depending on the support of a specific feature. However, we do need to keep in mind the case where a browser does not support feature queries, and handle the styles for those browsers accordingly.\n@supports not (shape-outside: polygon(100% 80%,20% 0,100% 0)) {\n /* Some CSS styles */\n}\nTo avoid confusion between and and or, these operators must be explicitly declared as opposed to using commas or spaces. To prevent confusion caused by precedence rules, and, or and not operators cannot be mixed without a layer of parentheses.\nThis rule is not valid and the styles within the block will be ignored.\n@supports (transition-property: background-color) or\n (animation-name: fade) and\n (transform: scale(1.5)) {\n /* Some CSS styles */\n}\nTo make it work, parentheses must be added either around the two properties adjacent to the or or the and operator like so:\n@supports ((transition-property: background-color) or\n (animation-name: fade)) and\n (transform: scale(1.5)) {\n /* Some CSS styles */\n}\n@supports (transition-property: background-color) or\n ((animation-name: fade) and\n (transform: scale(1.5))) {\n /* Some CSS styles */\n}\nThe current specification states that whitespace is required after a not and on both sides of an and or or, but this may change in a future version of the specification. It is acceptable to add extra parentheses even when they are not needed, but omission of parentheses is considered invalid.\nCascading web design\nI\u2019d like to introduce the concept of cascading web design, an approach made possible with feature queries. Browser update cycles are much shorter these days, so new features and bug fixes are being pushed out a lot more frequently as compared to the early days of the web.\nWith the maturation of web standards, browser behaviour is less unpredictable than before, but each browser will still have their respective quirks. Chances are, the latest features will not ship across all browsers at the same time. But you know what? That\u2019s perfectly fine. If we accept this as a feature of the web, instead of a bug, we\u2019ve just opened up a lot more web design possibilities.\nThe following example is a basic, responsive grid layout of items laid out with flexbox, as viewed on IE11.\n\nWe can add a block of styles within an @supports rule to apply CSS grid properties for browsers that support them to enhance this layout, like so:\n\nThe web is not a static medium. It is dynamic and interactive and we manipulate this medium by writing code to tell the browser what we want it to do. Rather than micromanaging the pixels in our designs, maybe it\u2019s time we cede control of our designs to the browsers that render them. This means being okay with your designs looking different across browsers and devices.\nAs mentioned earlier, CSS works best when various properties are combined. It\u2019s one of those things whose whole is greater than the sum of its parts. So feature queries, when combined with media queries, allow us to design layouts that are most effective in the environment they have to perform in.\nSuch an approach requires interpolative thinking, on multiple levels. As web designers and developers, we don\u2019t just think in one fixed dimension, we get to think about how our design will morph on a narrow screen, or on an older browser, in addition to how it will appear on a browser with the latest features.\nIn the following example, the layout on the left is what IE11 users will see, the one in the middle is what Firefox users will see, because Firefox doesn\u2019t support CSS shapes yet, but once it does, it will then look like the layout on the right, which is what Chrome users see now.\n\nWith the release of CSS Grid this year, we\u2019ve hit another milestone in the evolution of the web as a medium. The beauty of the web is its backwards compatibility and generous fault tolerance. Browser features are largely additive, holding onto the good parts and building on top of them, while deprecating the bits that didn\u2019t work well.\nFeature queries allow us to progressively enhance our CSS, establishing a basic level of user experience across the widest range of browsers, while building in more advanced functionality for browsers who can use them. And hopefully, this will allow more of us to create designs that truly embrace the nature of the web.", "year": "2017", "author": "Chen Hui Jing", "author_slug": "chenhuijing", "published": "2017-12-01T00:00:00+00:00", "url": "https://24ways.org/2017/cascading-web-design/", "topic": "code"} {"rowid": 206, "title": "Getting Hardboiled with CSS Custom Properties", "contents": "Custom Properties are a fabulous new feature of CSS and have widespread support in contemporary browsers. But how do we handle browsers without support for CSS Custom Properties? Do we wait until those browsers are lying dead in a ditch before we use them? Do we tool up and prop up our CSS using a post-processor? Or do we get tough? Do we get hardboiled?\nPreviously only pre-processing tools like LESS and Sass enabled developers to use variables in their stylesheets, but now Custom Properties have brought variables natively to CSS.\nHow do you write a custom property? It\u2019s hardly a mystery. Simply add two dashes to the start of a style rule. Like this:\n--color-text-default : black;\nIf you\u2019re more the underscore type, try this:\n--color_text_default : black;\nHyphens or underscores are allowed in property names, but don\u2019t be a chump and try to use spaces. \nCustom property names are also case-sensitive, so --color-text-default and --Color_Text_Default are two distinct properties.\nTo use a custom property in your style rules, var() tells a browser to retrieve the value of a property. In the next example, the browser retrieves the black colour from the color-text-default variable and applies it to the body element:\nbody {\n color : var(--color-text-default); \n}\nLike variables in LESS or Sass, CSS Custom Properties mean you don\u2019t have to be a dumb mug and repeat colour, font, or size values multiple times in your stylesheets. Unlike a preprocessor variable though, CSS Custom Properties use the cascade, can be modified by media queries and other state changes, and can also be manipulated by Javascript.\n(Serg Hospodarets wrote a fabulous primer on CSS Custom Properties where he dives deeper into the code and possible applications.)\nBrowser support\nNow it\u2019s about this time that people normally mention browser support. So what about support for CSS Custom Properties? Current versions of Chrome, Edge, Firefox, Opera, and Safari are all good. Internet Explorer 11 and before? Opera Mini? Nasty.\nSound familiar?\n\n Can I Use css-variables? Data on support for the css-variables feature across the major browsers from caniuse.com.\n\nNot to worry, we can manually check for Custom Property support in a browser by using an @support directive, like this:\n--color-text-default : black;\n\nbody {\n color : black; \n}\n\n@supports ((--foo : bar)) {\n body {\n color : var(--color-text-default); \n }\n}\nIn that example we first set body element text to black and then override that colour with a Custom Property value when the browser supports our fictitious foo bar variable.\nSubstitutions\nIf we reference a variable that hasn\u2019t been defined, that won\u2019t be a problem as browsers are smart enough to ignore the value altogether. If we need a cast iron alibi, use substitutions to specify a fall-back value.\nbody {\n color : var(--color-text-default, black); \n}\nSubstitutions are similar to font stacks in that they contain a comma separated list of values. If there\u2019s no value associated with a property, a browser will ignore it and move onto the next value in the list.\nPost-processing\nOf course we could use a post-processor plugin to turn Custom Properties into plain CSS, but hang on one goddam minute kiddo.\nHaven\u2019t we been down this road before? Didn\u2019t we engineer elaborate workarounds to enable us to use \u2018advanced\u2019 CSS3 properties like border-radius, CSS columns, and Flexbox in the past? We did what we had to do to get the job done, but came away feeling dirty.\nI think there\u2019s a better way, one that allows us to enjoy the benefits of CSS Custom Properties in browsers that support them, while providing an appropriate, but not identical experience, for people who use less capable browsers. Guess what, I\u2019ve been down this road before too. \n2Tone Stuff & Nonsense\nWhen Internet Explorer 6 was the big dumb browser everyone hated, I served two different designs on my website. \nFor the modern browsers of the time, mod arrows and targets were everywhere in glorious red, white, and blue, and I implemented all of them using CSS attribute selectors which were considered advanced at the time:\n[class=\"banner\"] {\n background-colour : red; \n}\nInternet Explorer 6 ignored any selectors it didn\u2019t understand, so people using that browser saw a simpler black and white, 2Tone-based design that I\u2019d implemented for them using class selectors:\n.banner {\n background-colour : black; \n}\n\n[class=\"banner\"] {\n background-colour : red; \n}\n\nYou don\u2019t have to be a detective to find out that most people thought I\u2019d lost my wits, but Microsoft even used my website as a reference when they tested attribute selectors in Internet Explorer 7. They did, as I suggested, \u201cStomp to da betta browser.\u201d\nDumb browsers look the other way\nSo how does this approach relate to tackling any lack of support for CSS Custom Properties? How can we take advantage of them without worrying about browsers with no support and having to implement complex workarounds, or spending hours specifying fallbacks that perfectly match our designs?\nTurns out, the answer is built into CSS, and always has been, because when browsers don\u2019t know what they\u2019re looking at, they look away. \nAll we have to do is first specify values for a simpler design first, and then follow that up with the values in our CSS Custom Properties:\nbody {\n color : black;\n color : var(--color-text-default, black); \n}\nAll browsers understand the first value (black,) and if they\u2018re smart enough to understand the second (var(--color-text-default)), they\u2019ll use it and override the first. If they\u2019re too damn stupid to understand the custom property value, they\u2019ll ignore it. Nobody dies.\nRepeat this for every style that contains a variable, baking an alternative, perhaps simpler design into your stylesheets for people who use less capable browsers, just like I did with Stuff & Nonsense.\nConclusion\nI doubt that anyone agrees with presenting a design that looks broken or unloved\u2014and I\u2019m not advocating for that\u2014but websites need not look the same in every browser. We can use substitutions to present a simpler design to people using less capable browsers.\nThe decision when to start using new CSS properties isn\u2018t always a technical one. Sometimes a change in attitude about browser support is all that\u2019s required. So get tough with dumb browsers and benefit from all the advantages that CSS Custom Properties offer. Get hardboiled.\nResources:\n\nIt\u2019s Time To Start Using CSS Custom Properties\u2014Smashing Magazine\nUsing CSS variables correctly\u2014Mike Riethmuller\nDeveloping Inspired Guides with CSS Custom Properties (variables)\u2014Andy Clarke", "year": "2017", "author": "Andy Clarke", "author_slug": "andyclarke", "published": "2017-12-13T00:00:00+00:00", "url": "https://24ways.org/2017/getting-hardboiled-with-css-custom-properties/", "topic": "code"} {"rowid": 209, "title": "Feeding the Audio Graph", "contents": "In 2004, I was given an iPod.\nI count this as one of the most intuitive pieces of technology I\u2019ve ever owned. It wasn\u2019t because of the the snazzy (colour!) menus or circular touchpad. I loved how smoothly it fitted into my life. I could plug in my headphones and listen to music while I was walking around town. Then when I got home, I could plug it into an amplifier and carry on listening there.\nThere was no faff. It didn\u2019t matter if I could find my favourite mix tape, or if my WiFi was flakey - it was all just there.\nNowadays, when I\u2019m trying to pair my phone with some Bluetooth speakers, or can\u2019t find my USB-to-headphone jack, or even access any music because I don\u2019t have cellular reception; I really miss this simplicity.\nThe Web Audio API\nI think the Web Audio API feels kind of like my iPod did.\nIt\u2019s different from most browser APIs - rather than throwing around data, or updating DOM elements - you plug together a graph of audio nodes, which the browser uses to generate, process, and play sounds.\nThe thing I like about it is that you can totally plug it into whatever you want, and it\u2019ll mostly just work.\nSo, let\u2019s get started. First of all we want an audio source.\n