{"database": "24ways", "table": "articles", "is_view": false, "human_description_en": "where author = \"Andy Clarke\", author_slug = \"andyclarke\" and topic = \"code\"", "rows": [[206, "Getting Hardboiled with CSS Custom Properties", "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", "2017", "Andy Clarke", "andyclarke", "2017-12-13T00:00:00+00:00", "https://24ways.org/2017/getting-hardboiled-with-css-custom-properties/", "code"], [246, "Designing Your Site Like It\u2019s 1998", "It\u2019s 20 years to the day since my wife and I started Stuff & Nonsense, our little studio and my outlet for creative ideas on the web. To celebrate this anniversary\u2014and my fourteenth contribution to 24 ways\u2014 I\u2019d like to explain how I would\u2019ve developed a design for Planes, Trains and Automobiles, one of my favourite Christmas films.\nMy design for Planes, Trains and Automobiles is fixed at 800px wide.\nDeveloping a <frameset> framework\nI\u2019ll start by using frames to set up the framework for this new website. Frames are individual pages\u2014one for navigation, the other for my content\u2014pulled together to form a frameset. Space is limited on lower-resolution screens, so by using frames I can ensure my navigation always remains visible. I can include any number of frames inside a <frameset> element.\nI add two rows to my <frameset>; the first is for my navigation and is 50px tall, the second is for my content and will resize to fill any available space. As I don\u2019t want frame borders or any space between my frames, I set frameborder and framespacing attributes to 0:\n<frameset frameborder=\"0\" framespacing=\"0\" rows=\"50,*\">\n[\u2026]\n</frameset>\nNext I add the source of my two frame documents. I don\u2019t want people to be able to resize or scroll my navigation, so I add the noresize attribute to that frame:\n<frameset frameborder=\"0\" framespacing=\"0\" rows=\"50,*\">\n<frame noresize scrolling=\"no\" src=\"nav.html\">\n<frame src=\"content.html\">\n</frameset>\nI do want links from my navigation to open in the content frame, so I give each <frame> a name so I can specify where I want links to open:\n<frameset frameborder=\"0\" framespacing=\"0\" rows=\"50,*\">\n<frame name=\"navigation\" noresize scrolling=\"no\" src=\"nav.html\">\n<frame name=\"content\" src=\"content.html\">\n</frameset>\nThe framework for this website is simple as it contains only two horizontal rows. Should I need a more complex layout, I can nest as many framesets\u2014and as many individual documents\u2014as I need:\n<frameset rows=\"50,*\">\n <frame name=\"navigation\">\n <frameset cols=\"25%,*\">\n  <frame name=\"sidebar\">\n  <frame name=\"content\">\n </frameset>\n</frameset>\nLetterbox framesets were common way to deal with multiple screen sizes. In a letterbox, the central frameset had a fixed height and width, while the frames on the top, right, bottom, and left expanded to fill any remaining space.\nHandling older browsers\nSadly not every browser supports frames, so I should send a helpful message to people who use older browsers asking them to upgrade. Happily, I can do that using noframes content:\n<noframes>\n<body>\n<p>This page uses frames, but your browser doesn\u2019t support them. \n    Please upgrade your browser.</p>\n</body>\n</noframes>\nForcing someone back into a frame\nSometimes, someone may follow a link to a page from a portal or search engine, or they might attempt to open it in a new window or tab. If that page properly belongs inside a <frameset>, people could easily miss out on other parts of a design. This short script will prevent this happening and because it\u2019s vanilla Javascript, it doesn\u2019t require a library such as jQuery:\n<script type=\"text/javascript\">\nif (top == self) {\n  location = 'frameset.html';\n}\n</script>\n\nLaying out my page\nBefore starting my layout, I add a few basic background and colour styles. I must include these attributes in every page on my website:\n<body background=\"img/container.jpg\" bgcolor=\"#fef7fb\" \n    link=\"#245eab\" alink=\"#245eab\" vlink=\"#3c146e\" text=\"#000000\">\nI want absolute control over how people experience my design and don\u2019t want to allow it to stretch, so I first need a <table> which limits the width of my layout to 800px. The align attribute will keep this <table> in the centre of someone\u2019s screen:\n<table width=\"800\" align=\"center\">\n <tr>\n  <td>[\u2026]</td>\n </tr>\n</table>\nAlthough they were developed for displaying tabular information, the cells and rows which make up the <table> element make it ideal for the precise implementation of a design. I need several tables\u2014often nested inside each other\u2014to implement my design. These include tables for a banner and three rows of content:\n<table width=\"800\" align=\"center\">\n <table>[\u2026]</table>\n <table>\n  <table>\n   <table>[\u2026]</table>\n  </table>\n </table>\n <table>[\u2026]</table>\n <table>[\u2026]</table>\n</table>\nThe width of the first table\u2014used for my banner\u2014is fixed to match the logo it contains. As I don\u2019t need borders, padding, or spacing between these cells, I use attributes to remove them:\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"587\" align=\"center\">\n <tr>\n  <td><img src=\"logo.gif\" border=\"0\" width=\"587\" alt=\"Logo\"></td>\n </tr>\n</table>\nThe next table\u2014which contains the largest image, introduction, and a call-to-action\u2014is one of the most complex parts of my design, so I need to ensure its layout is pixel perfect. To do that I add an extra row at the top of this table and fill each of its cells with tiny transparent images:\n<tr>\n <td><img src=\"spacer.gif\" width=\"593\" height=\"1\"></td>\n <td><img src=\"spacer.gif\" width=\"207\" height=\"1\"></td>\n</tr>\nThe height and width of these \u201cshims\u201d or \u201cspacers\u201d is only 1px but they will stretch to any size without increasing their weight on the page. This makes them perfect for performant website development.\nFor the hero of this design, I splice up the large image into three separate files and apply each slice as a background to the table cells. I also match the height of those cells to the background images:\n<tr>\n <td background=\"slice-1.jpg\" height=\"473\">\u00a0</td>\n <td background=\"slice-2.jpg\" height=\"473\">[\u2026]</td>\n</tr>\n\n<tr>\n <td background=\"slice-3.jpg\" height=\"388\">\u00a0</td>\n</tr>\nI use tables and spacer images throughout the rest of this design to lay out the various types of content with perfect precision. For example, to add a single-pixel border around my two columns of content, I first apply a blue background to an outer table along with 1px of cellspacing, then simply nest an inner table\u2014this time with a white background\u2014inside it:\n<table border=\"0\" cellpadding=\"1\" cellspacing=\"0\">\n <tr>\n  <td>\n   <table bgcolor=\"#ffffff\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n[\u2026]\n   </table>\n  </td>\n </tr>\n</table>\nAdding details\nTables are fabulous tools for laying out a page, but they\u2019re also useful for implementing details on those pages. I can use a table to add a gradient background, rounded corners, and a shadow to the button which forms my \u201cBuy the DVD\u201d call-to-action. First, I splice my button graphic into three slices; two fixed-width rounded ends, plus a narrow gradient which stretches and makes this button responsive. Then, I add those images as backgrounds and use spacers to perfectly size my button:\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n <tr>\n  <td background=\"btn-1.jpg\" border=\"0\" height=\"48\" width=\"30\"><img src=\"spacer.gif\" width=\"30\" height=\"1\"></td>\n\n  <td background=\"btn-2.jpg\" border=\"0\" height=\"48\">\n   <center>\n    <a href=\"\" target=\"_blank\"><b>Buy the DVD</b></a>\n   </center>\n  </td>\n\n  <td background=\"btn-3.jpg\" border=\"0\" height=\"48\" width=\"30\"><img src=\"spacer.gif\" width=\"30\" height=\"1\"></td>\n </tr>\n</table>\nI use those same elements to add details to headlines and lists too. Adding a \u201cbullet\u201d to each item in a list needs only two additional table cells, a circular graphic, and a spacer:\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n <tr>\n  <td width=\"10\"><img src=\"li.gif\" border=\"0\" width=\"8\" height=\"8\">\u00a0</td>\n  <td><img src=\"spacer.gif\" width=\"10\" height=\"1\">\u00a0</td>\n  <td>Directed by John Hughes</td>\n </tr>\n</table>\nImplementing a typographic hierarchy\nSo far I\u2019ve explained how to use frames, tables, and spacers to develop a layout for my content, but what about styling that content? I use <font> elements to change the typeface from the browser\u2019s default to any font installed on someone\u2019s device:\n<font face=\"Arial\">Planes, Trains and Automobiles is a comedy film [\u2026]</font>\nTo adjust the size of those fonts, I use the size attribute and a value between the smallest (1) and the largest (7) where 3 is the browser\u2019s default. I use a size of 4 for this headline and 2 for the text which follows:\n<font face=\"Arial\" size=\"4\"><b>Steve Martin</b></font>\n\n<font face=\"Arial\" size=\"2\">An American actor, comedian, writer, producer, and musician.</font>\nWhen I need to change the typeface, perhaps from a sans-serif like Arial to a serif like Times New Roman, I must change the value of the face attribute on every element on all pages on my website.\nNB: I use as many <br> elements as needed to create space between headlines and paragraphs.\nView the final result (and especially the source.)\nMy modern day design for Planes, Trains and Automobiles.\nI can imagine many people reading this and thinking \u201cThis is terrible advice because we don\u2019t develop websites like this in 2018.\u201d That\u2019s true.\nWe have the ability to embed any number of web fonts into our products and websites and have far more control over type features, leading, ligatures, and sizes:\nfont-variant-caps: titling-caps;\nfont-variant-ligatures: common-ligatures;\nfont-variant-numeric: oldstyle-nums;\nGrid has simplified the implementation of even the most complex compound grid down to just a few lines of CSS:\nbody {\n  display: grid;\n  grid-template-columns: 3fr 1fr 2fr 2fr 1fr 3fr;\n  grid-template-rows: auto;\n  grid-column-gap: 2vw;\n  grid-row-gap: 1vh;\n}\nFlexbox has made it easy to develop flexible components such as navigation links:\nnav ul { display: flex; }\nnav li { flex: 1; }\nJust one line of CSS can create multiple columns of fluid type:\nmain { column-width: 12em; }\nCSS Shapes enable text to flow around irregular shapes including polygons:\n[src*=\"main-img\"] {\n  float: left;\n  shape-outside: polygon(\u2026);\n}\nToday, we wouldn\u2019t dream of using images and a table to add a gradient, rounded corners, and a shadow to a button or link, preferring instead:\n.btn {\n  background: linear-gradient(#8B1212, #DD3A3C);\n  border-radius: 1em;\n  box-shadow: 0 2px 4px 0 rgba(0,0,0,0.50), inset 0 -1px 1px 0 rgba(0,0,0,0.50);\n}\nCSS Custom Properties, feature and media queries, filters, pseudo-elements, and SVG; the list of advances in HTML, CSS, and other technologies goes on. So does our understanding of how best to use them by separating content, structure, presentation, and behaviour. As 2018 draws to a close, we\u2019re certain we know how to design and develop products and websites better than we did at the end of 1998.\nStrange as it might seem looking back, in 1998 we were also certain our techniques and technologies were the best for the job. That\u2019s why it\u2019s dangerous to believe with absolute certainty that the frameworks and tools we increasingly rely on today\u2014tools like Bootstrap, Bower, and Brunch, Grunt, Gulp, Node, Require, React, and Sass\u2014will be any more relevant in the future than <font> elements, frames, layout tables, and spacer images are today.\nI have no prediction for what the web will be like twenty years from now. However, I want to believe we\u2019ll build on what we\u2019ve learned during these past two decades about the importance of accessibility, flexibility, and usability, and that the mistakes we made while infatuated by technologies won\u2019t be repeated.\n\nHead over to my website if you\u2019d like to read about how I\u2019d implement my design for \u2018Planes, Trains and Automobiles\u2019 today.", "2018", "Andy Clarke", "andyclarke", "2018-12-23T00:00:00+00:00", "https://24ways.org/2018/designing-your-site-like-its-1998/", "code"]], "truncated": false, "table_rows_count": 336, "filtered_table_rows_count": 2, "expanded_columns": [], "expandable_columns": [], "columns": ["rowid", "title", "contents", "year", "author", "author_slug", "published", "url", "topic"], "primary_keys": [], "units": {}, "query": {"sql": "select rowid, * from articles where \"author\" = :p0 and \"author_slug\" = :p1 and \"topic\" = :p2 order by rowid limit 101", "params": {"p0": "Andy Clarke", "p1": "andyclarke", "p2": "code"}}, "facet_results": {}, "suggested_facets": [], "next": null, "next_url": null, "query_ms": 16.83831214904785}