CINXE.COM
CSS Guidelines (2.2.5) – High-level advice and guidelines for writing sane, manageable, scalable CSS
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, minimum-scale=1.0"> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com"> <link rel="preconnect" href="https://cdn.carbonads.com"> <link rel="preconnect" href="https://www.google-analytics.com"> <link rel="dns-prefetch" href="https://fonts.googleapis.com"> <link rel="dns-prefetch" href="https://fonts.gstatic.com"> <link rel="dns-prefetch" href="https://cdn.carbonads.com"> <link rel="dns-prefetch" href="https://www.google-analytics.com"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium+Web:200%7CMerriweather:300italic,300,700,700italic" /> <style> /*! * inuitcss, by @csswizardry * * github.com/inuitcss | inuitcss.com *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}body,h1,h2,h3,h4,h5,h6,p,blockquote,pre,dl,dd,ol,ul,form,fieldset,legend,figure,table,th,td,caption,hr{margin:0;padding:0}abbr[title],dfn[title]{cursor:help}u,ins{text-decoration:none}ins{border-bottom:1px solid}html{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*,*:before,*:after{-webkit-box-sizing:inherit;-moz-box-sizing:inherit;box-sizing:inherit}h1,h2,h3,h4,h5,h6,ul,ol,dl,blockquote,p,address,hr,table,fieldset,figure,pre,.box--promo,[id="carbonads"]{margin-bottom:24px;margin-bottom:1.5rem}ul,ol,dd{margin-left:48px;margin-left:3rem}html{font-size:1em;line-height:1.5;background-color:#fafafa;color:#222;overflow-y:scroll;min-height:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}html{font-family:Merriweather, Georgia, serif;font-weight:300;background-color:#fafafa}h1,h2,h3,h4,h5,h6{font-family:"Titillium Web", "Helvetica Neue", Helvetica, sans-serif;color:#6897c5;font-weight:200;text-shadow:0 -1px rgba(0,0,0,0.1),0 1px #fff}h1,.alpha{font-size:36px;font-size:2.25rem;line-height:1.333333333}@media screen and (min-width: 45em){h1,.alpha{font-size:64px;font-size:4rem;line-height:1.125}}@media screen and (min-width: 64em){h1,.alpha{font-size:64px;font-size:4rem;line-height:1.125}}h2,.beta{font-size:28px;font-size:1.75rem;line-height:1.714285714}@media screen and (min-width: 45em){h2,.beta{font-size:36px;font-size:2.25rem;line-height:1.333333333}}h3,.gamma{font-size:24px;font-size:1.5rem;line-height:1}@media screen and (min-width: 45em){h3,.gamma{font-size:28px;font-size:1.75rem;line-height:1.714285714}}h4,.delta{font-size:20px;font-size:1.25rem;line-height:1.2}@media screen and (min-width: 45em){h4,.delta{font-size:24px;font-size:1.5rem;line-height:1}}h5,.epsilon{font-size:18px;font-size:1.125rem;line-height:1.333333333}@media screen and (min-width: 45em){h5,.epsilon{font-size:20px;font-size:1.25rem;line-height:1.2}}h6,.zeta{font-size:16px;font-size:1rem;line-height:1.5}.site-title{margin-bottom:72px}a,b,strong,dt{font-weight:700}a{color:#6897c5;text-decoration:none}a:hover,a:active,a:focus{text-decoration:underline}code,kbd,samp{color:#859900;font-family:Operator Mono, Inconsolata, Monaco, Consolas, "Andale Mono", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;font-weight:normal;font-style:normal}pre{white-space:pre;word-wrap:normal;overflow:auto;padding:12px;margin-right:-12px;margin-left:-12px;background-color:#333;border-radius:3px}@media screen and (min-width: 64em){pre{margin-right:-24px;margin-left:-24px;padding:24px}}pre,pre code,pre kbd,pre samp{color:#fff}q{font-style:italic;quotes:"‘" "’" "“" "”"}q:before{content:open-quote}q:after{content:close-quote}blockquote{color:#666;font-style:italic;padding-right:24px;padding-left:24px}blockquote p{margin-bottom:0}blockquote p+p{text-indent:24px}hr{border:none;border-top:5px solid rgba(0,0,0,0.05);margin-bottom:67px}.hr-minor{border-top-width:1px;width:50%;margin-right:auto;margin-left:auto;margin-bottom:23px}mark,.highlight:target{background-color:yellow;color:black}li>ul,li>ol{margin-bottom:0}img{max-width:100%;font-style:italic;vertical-align:middle}.gm-style img,img[width],img[height]{max-width:none}.wrapper{max-width:48em;margin-right:auto;margin-left:auto;padding-right:24px;padding-left:24px}.btn{display:inline-block;vertical-align:middle;font:inherit;text-align:center;margin:0;cursor:pointer;overflow:visible;padding:10px 22px;background-color:#6897c5;border:2px solid #6897c5}.btn,.btn:hover,.btn:active,.btn:focus{text-decoration:none;color:#fff}.btn::-moz-focus-inner{border:0;padding:0}.btn--full{width:100%}.box{display:block;padding:24px}.box>:last-child{margin-bottom:0}.page-head{padding-top:10%;padding-bottom:10%;background-color:#6897c5;margin-bottom:48px}.page-foot{padding-top:120px;text-align:center;font-size:12px;font-size:.75rem;line-height:2;font-family:sans-serif}.version{font-size:20px;font-size:1.25rem;line-height:1.2}.logo-wrap{position:relative;width:75%;padding-top:25%;margin-right:auto;margin-left:auto;overflow:hidden}.logo{position:absolute;top:0;left:0}.logo__character{fill:#6897c5}.page-head .logo__character{fill:#fff}.logo__punctuation{fill:#c4d6e8}.page-head .logo__punctuation{opacity:0.5;fill:#fff}.btn{font-weight:700}.btn--secondary{background:none}.btn--secondary,.btn--secondary:hover,.btn--secondary:active,.btn--secondary:focus{color:#6897c5}.btn--tertiary{background:none}.btn--tertiary,.btn--tertiary:hover,.btn--tertiary:active,.btn--tertiary:focus{color:#fff;border-color:inherit}.box{border-radius:3px}.box--outdent{margin-right:-12px;margin-left:-12px}@media screen and (min-width: 64em){.box--outdent{margin-right:-24px;margin-left:-24px}}.box--promo{color:#fff;background-color:#6897c5}[id="carbonads"]{font-size:12px;font-size:.75rem;padding:12px;font-family:sans-serif;text-align:center;background-color:#f2f2f2;border-radius:3px;border:1px solid #e6e6e6}[id="carbonads"],[id="carbonads"] a{color:#999}.carbon-wrap{display:block}.carbon-img{display:block;padding-bottom:12px}.carbon-text{display:block;overflow:hidden}.carbon-img:hover+.carbon-text{text-decoration:underline}.carbon-poweredby{font-weight:normal}.clearfix:after,.box:after,.carbon-wrap:after{content:"";display:table;clear:both}.hide{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px 1px 1px 1px);clip:rect(1px, 1px, 1px, 1px)}@media screen and (max-width: 44.9375em){.hide-palm{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px 1px 1px 1px);clip:rect(1px, 1px, 1px, 1px)}}@media screen and (min-width: 45em) and (max-width: 63.9375em){.hide-lap{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px 1px 1px 1px);clip:rect(1px, 1px, 1px, 1px)}}@media screen and (min-width: 45em){.hide-lap-and-up{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px 1px 1px 1px);clip:rect(1px, 1px, 1px, 1px)}}@media screen and (max-width: 63.9375em){.hide-portable{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px 1px 1px 1px);clip:rect(1px, 1px, 1px, 1px)}}@media screen and (min-width: 64em){.hide-desk{position:absolute !important;height:1px;width:1px;overflow:hidden;clip:rect(1px 1px 1px 1px);clip:rect(1px, 1px, 1px, 1px)}}.text-center{text-align:center !important}@media print{@page{margin:0}*{background:none !important;color:#000 !important}html{font-size:10pt;line-height:1.4;max-width:72ch;margin-right:auto;margin-left:auto}a{text-decoration:underline}a:after{content:" (" attr(href) ")";font:menu}ul,ol,pre{page-break-inside:avoid}pre{padding:0;padding-left:1em;border-left:5px solid;border-radius:0;margin-right:0;margin-left:0}.page-head{border-bottom:1px solid #999}.page-head .logo__character{fill:black}.page-head .logo__punctuation{fill:#999}[id="carbonads"]{display:none}} /*# sourceMappingURL=main.min.css.map */ </style> <title>CSS Guidelines (2.2.5) – High-level advice and guidelines for writing sane, manageable, scalable CSS</title> <meta name="description" content="High-level advice and guidelines for writing sane, manageable, scalable CSS"> <link rel="canonical" href="https://cssguidelin.es/"> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:site" content="@cssguidelines"> <meta name="twitter:domain" content="cssguidelin.es"> <meta name="twitter:creator" content="@csswizardry"> <meta name="twitter:title" content="CSS Guidelines"> <meta name="twitter:image:src" content="https://cssguidelin.es/twitter-card.png"> <meta name="twitter:description" content="High-level advice and guidelines for writing sane, manageable, scalable CSS"> <link rel="shortcut icon" href="/icon.png"> <link rel="apple-touch-icon-precomposed" href="/icon.png"> <meta name="theme-color" content="#6897c5"> <link rel="manifest" href="/manifest.json"> </head> <body> <header class="page-head"> <div class="wrapper"> <div class="logo-wrap"> <svg class="logo" preserveAspectRatio="xMinYMin meet" viewBox="0 0 180 60" xmlns="http://www.w3.org/2000/svg"><g><path d="M175.182 46.117c-.754-.453-1.322-1.046-1.704-1.777-.382-.731-.573-1.571-.573-2.519v-2.581c0-1.381-.258-2.367-.775-2.959-.516-.592-1.353-.889-2.51-.889-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232 1.808 0 3.195.471 4.16 1.414.966.943 1.449 2.393 1.449 4.35v2.612c0 1.123.269 1.973.806 2.55.537.577 1.379.865 2.526.865.351 0 .602.077.751.232.15.155.225.428.225.819 0 .391-.075.664-.225.819-.15.155-.4.232-.751.232-1.147 0-1.988.286-2.526.858-.537.572-.806 1.419-.806 2.542v3.292c0 1.968-.483 3.42-1.449 4.358-.966.938-2.353 1.406-4.16 1.406-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232 1.157 0 1.994-.296 2.51-.889.516-.592.775-1.579.775-2.959v-3.261c0-.948.191-1.79.573-2.527.382-.737.95-1.332 1.704-1.785zm-18.165-4.559c0-.361.07-.698.209-1.012.139-.314.328-.59.566-.827.238-.237.514-.425.829-.564.315-.139.653-.209 1.015-.209.362 0 .7.07 1.015.209.315.139.591.327.829.564.238.237.426.513.566.827.139.314.209.652.209 1.012 0 .361-.07.698-.209 1.012-.139.314-.328.59-.566.827-.238.237-.514.425-.829.564-.315.139-.653.209-1.015.209-.362 0-.7-.07-1.015-.209-.315-.139-.591-.327-.829-.564-.238-.237-.426-.513-.566-.827-.139-.314-.209-.652-.209-1.012zm.852 15.917c-.114.216-.261.376-.442.479-.181.103-.374.155-.581.155-.145 0-.279-.023-.403-.07-.124-.046-.232-.113-.325-.201-.093-.088-.158-.193-.194-.317-.036-.124-.039-.268-.008-.433l1.611-7.448c.093-.412.362-.618.806-.618h3.006c.258 0 .431.095.519.286.088.191.059.42-.085.688l-3.905 7.479zm-.832-38.648c0-.361.07-.698.209-1.012.139-.314.328-.59.566-.827.238-.237.514-.425.829-.564.315-.139.653-.209 1.015-.209.362 0 .7.07 1.015.209.315.139.591.327.829.564.238.237.426.513.566.827.139.314.209.652.209 1.012 0 .361-.07.698-.209 1.012-.139.314-.328.59-.566.827-.238.237-.514.425-.829.564-.315.139-.653.209-1.015.209-.362 0-.7-.07-1.015-.209-.315-.139-.591-.327-.829-.564-.238-.237-.426-.513-.566-.827-.139-.314-.209-.652-.209-1.012zm0-9.736c0-.361.07-.698.209-1.012.139-.314.328-.59.566-.827.238-.237.514-.425.829-.564.315-.139.653-.209 1.015-.209.362 0 .7.07 1.015.209.315.139.591.327.829.564.238.237.426.513.566.827.139.314.209.652.209 1.012 0 .361-.07.698-.209 1.012-.139.314-.328.59-.566.827-.238.237-.514.425-.829.564-.315.139-.653.209-1.015.209-.362 0-.7-.07-1.015-.209-.315-.139-.591-.327-.829-.564-.238-.237-.426-.513-.566-.827-.139-.314-.209-.652-.209-1.012zm-97.658 4.559c.754.453 1.322 1.048 1.704 1.785.382.737.573 1.579.573 2.527v3.261c0 .69.062 1.28.186 1.769.124.489.318.889.581 1.198.263.309.604.533 1.023.672.418.139.917.209 1.495.209.351 0 .602.077.751.232.15.155.225.428.225.819 0 .391-.075.664-.225.819-.15.155-.4.232-.751.232-1.808 0-3.195-.469-4.16-1.406-.966-.938-1.449-2.39-1.449-4.358v-3.292c0-1.123-.269-1.97-.806-2.542-.537-.572-1.379-.858-2.526-.858-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232 1.147 0 1.988-.288 2.526-.865.537-.577.806-1.427.806-2.55v-2.612c0-1.957.483-3.407 1.449-4.35.966-.943 2.353-1.414 4.16-1.414.351 0 .602.077.751.232.15.155.225.428.225.819 0 .391-.075.664-.225.819-.15.155-.4.232-.751.232-.578 0-1.077.07-1.495.209-.418.139-.759.363-1.023.672-.263.309-.457.708-.581 1.198-.124.489-.186 1.079-.186 1.769v2.581c0 .948-.191 1.787-.573 2.519-.382.731-.95 1.324-1.704 1.777z" class="logo__punctuation"/><path d="M143.625 52.901c0 .361-.085.618-.256.773-.17.155-.473.232-.906.232-.434 0-.736-.077-.906-.232-.17-.155-.256-.412-.256-.773v-3.709c0-.361.085-.618.256-.773.17-.155.473-.232.906-.232.227 0 .403.052.527.155.124.103.227.263.31.479.382.999 1.007 1.723 1.875 2.171.868.448 2.019.672 3.455.672 1.24 0 2.169-.219 2.789-.657.62-.438.93-1.012.93-1.723 0-.371-.119-.667-.356-.889-.238-.221-.558-.399-.961-.533-.455-.155-.981-.268-1.58-.34-.599-.072-1.229-.144-1.89-.216-.661-.072-1.32-.165-1.976-.278-.656-.113-1.263-.278-1.821-.495-.351-.134-.671-.299-.961-.495-.289-.196-.54-.428-.751-.695-.212-.268-.377-.577-.496-.927-.119-.35-.178-.752-.178-1.205 0-.69.139-1.301.418-1.831.279-.531.664-.976 1.154-1.337.491-.361 1.069-.634 1.735-.819.666-.185 1.392-.278 2.177-.278 1.033 0 1.96.152 2.781.456.821.304 1.526.719 2.115 1.244v-.695c0-.361.085-.618.256-.773.17-.155.473-.232.906-.232.434 0 .736.077.906.232.17.155.256.412.256.773v2.936c0 .361-.085.618-.256.773-.17.155-.473.232-.906.232-.351 0-.599-.134-.744-.402-.238-.443-.524-.814-.86-1.113-.336-.299-.723-.536-1.162-.711-.439-.175-.922-.299-1.449-.371-.527-.072-1.09-.108-1.689-.108-1.002 0-1.784.175-2.347.525-.563.35-.844.85-.844 1.499 0 .34.111.613.333.819.222.206.529.371.922.495.434.144.94.25 1.518.317.578.067 1.188.134 1.828.201.64.067 1.286.149 1.937.247s1.255.25 1.813.456c.382.144.733.317 1.054.518.32.201.597.443.829.726.232.283.413.613.542.989.129.376.194.811.194 1.306 0 .69-.132 1.319-.395 1.885-.263.567-.651 1.053-1.162 1.46-.511.407-1.141.721-1.89.943-.749.221-1.604.332-2.564.332-1.126 0-2.11-.155-2.952-.464-.842-.309-1.578-.778-2.208-1.406v.865zm-16.44-5.903c.083 1.556.514 2.722 1.294 3.5s1.893 1.167 3.339 1.167c1.043 0 2.056-.118 3.037-.355.981-.237 1.828-.561 2.541-.974.331-.185.607-.201.829-.046.222.155.4.397.535.726.145.33.176.626.093.889-.083.263-.294.482-.635.657-.403.196-.85.376-1.34.541-.491.165-1.012.306-1.565.425-.553.118-1.123.211-1.712.278-.589.067-1.183.1-1.782.1-1.136 0-2.143-.173-3.021-.518-.878-.345-1.617-.84-2.216-1.484-.599-.644-1.056-1.427-1.371-2.349-.315-.922-.473-1.965-.473-3.129 0-1.123.183-2.145.55-3.067.367-.922.875-1.71 1.526-2.364.651-.654 1.428-1.159 2.332-1.514.904-.355 1.898-.533 2.983-.533 1.147 0 2.159.178 3.037.533.878.355 1.619.847 2.224 1.476.604.628 1.072 1.375 1.402 2.241.331.865.527 1.813.589 2.843 0 .35-.075.598-.225.742-.15.144-.4.216-.751.216h-11.218zm4.943-5.81c-1.291 0-2.347.322-3.169.966-.821.644-1.361 1.538-1.619 2.681h9.467c-.217-1.164-.708-2.063-1.472-2.697-.764-.634-1.834-.95-3.207-.95zm-22.617.201h-1.58c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h2.774c.351 0 .602.077.751.232.15.155.225.428.225.819v1.854c.682-1.061 1.477-1.867 2.386-2.418.909-.551 1.896-.827 2.96-.827.713 0 1.353.118 1.921.355.568.237 1.051.572 1.449 1.004.398.433.702.961.914 1.584.212.623.318 1.321.318 2.094v7.479h1.271c.351 0 .602.077.751.232.15.155.225.428.225.819 0 .391-.075.664-.225.819-.15.155-.4.232-.751.232h-5.02c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h1.426v-7.248c0-.443-.052-.847-.155-1.213-.103-.366-.258-.68-.465-.943-.207-.263-.467-.466-.782-.61-.315-.144-.684-.216-1.108-.216-.661 0-1.291.144-1.89.433-.599.288-1.126.69-1.58 1.205-.455.515-.816 1.128-1.085 1.839-.269.711-.403 1.489-.403 2.333v4.42h1.426c.351 0 .602.077.751.232.15.155.225.428.225.819 0 .391-.075.664-.225.819-.15.155-.4.232-.751.232h-5.02c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h1.271v-10.076zm-12.732 0h-3.92c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h5.268c.351 0 .602.077.751.232.15.155.225.428.225.819v11.126h4.974c.351 0 .602.077.751.232.15.155.225.428.225.819 0 .391-.075.664-.225.819-.15.155-.4.232-.751.232h-12.148c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h4.85v-10.076zm2.324-5.872c0 .361-.098.618-.294.773-.196.155-.589.232-1.178.232s-.981-.077-1.178-.232c-.196-.155-.294-.412-.294-.773v-2.009c0-.361.098-.618.294-.773.196-.155.589-.232 1.178-.232s.981.077 1.178.232c.196.155.294.412.294.773v2.009zm-18.532-.124h-4.23c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h5.578c.351 0 .602.077.751.232.15.155.225.428.225.819v17.122h4.974c.351 0 .602.077.751.232.15.155.225.428.225.819 0 .391-.075.664-.225.819-.15.155-.4.232-.751.232h-12.148c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h4.85v-16.071zm62.026-20.862c.083 1.556.514 2.722 1.294 3.5s1.893 1.167 3.339 1.167c1.043 0 2.056-.118 3.037-.355.981-.237 1.828-.561 2.541-.974.331-.185.607-.201.829-.046.222.155.4.397.535.726.145.33.176.626.093.889-.083.263-.294.482-.635.657-.403.196-.85.376-1.34.541-.491.165-1.012.306-1.565.425-.553.118-1.123.211-1.712.278-.589.067-1.183.1-1.782.1-1.136 0-2.143-.173-3.021-.518-.878-.345-1.617-.84-2.216-1.484-.599-.644-1.056-1.427-1.371-2.349-.315-.922-.473-1.965-.473-3.129 0-1.123.183-2.145.55-3.067.367-.922.875-1.71 1.526-2.364.651-.654 1.428-1.159 2.332-1.514.904-.355 1.898-.533 2.983-.533 1.147 0 2.159.178 3.037.533.878.355 1.619.847 2.224 1.476.604.628 1.072 1.375 1.402 2.241.331.865.527 1.813.589 2.843 0 .35-.075.598-.225.742-.15.144-.4.216-.751.216h-11.218zm4.943-5.81c-1.291 0-2.347.322-3.169.966-.821.644-1.361 1.538-1.619 2.681h9.467c-.217-1.164-.708-2.063-1.472-2.697-.764-.634-1.834-.95-3.207-.95zm-9.199 10.276c.351 0 .602.077.751.232.15.155.225.428.225.819 0 .391-.075.664-.225.819-.15.155-.4.232-.751.232h-2.464c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819v-1.236c-.64.834-1.387 1.481-2.239 1.939-.852.458-1.795.688-2.828.688-.961 0-1.849-.162-2.665-.487-.816-.325-1.521-.791-2.115-1.399-.594-.608-1.061-1.35-1.402-2.225-.341-.876-.511-1.87-.511-2.982 0-1.113.17-2.107.511-2.982.341-.876.808-1.617 1.402-2.225.594-.608 1.299-1.074 2.115-1.399.816-.325 1.704-.487 2.665-.487 1.033 0 1.955.209 2.766.626.811.417 1.526 1.012 2.146 1.785v-6.738h-3.13c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h4.478c.351 0 .602.077.751.232.15.155.225.428.225.819v17.122h1.271zm-3.595-4.651c0-.762-.119-1.442-.356-2.04-.238-.598-.568-1.1-.992-1.507-.424-.407-.927-.719-1.511-.935-.584-.216-1.216-.325-1.898-.325-.702 0-1.327.118-1.875.355-.547.237-1.007.569-1.379.997-.372.428-.656.935-.852 1.522-.196.587-.294 1.231-.294 1.932 0 .701.098 1.344.294 1.932.196.587.48 1.095.852 1.522.372.428.832.76 1.379.997s1.172.355 1.875.355c.682 0 1.314-.108 1.898-.325.584-.216 1.087-.528 1.511-.935.424-.407.754-.909.992-1.507.238-.598.356-1.277.356-2.04zm-20.241-5.424h-3.92c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h5.268c.351 0 .602.077.751.232.15.155.225.428.225.819v11.126h4.974c.351 0 .602.077.751.232.15.155.225.428.225.819 0 .391-.075.664-.225.819-.15.155-.4.232-.751.232h-12.148c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h4.85v-10.076zm2.324-5.872c0 .361-.098.618-.294.773-.196.155-.589.232-1.178.232s-.981-.077-1.178-.232c-.196-.155-.294-.412-.294-.773v-2.009c0-.361.098-.618.294-.773.196-.155.589-.232 1.178-.232s.981.077 1.178.232c.196.155.294.412.294.773v2.009zm-11.012 15.948c.351 0 .602.077.751.232.15.155.225.428.225.819 0 .391-.075.664-.225.819-.15.155-.4.232-.751.232h-2.464c-.351 0-.602-.075-.751-.224-.15-.149-.225-.42-.225-.811v-1.87c-.682 1.061-1.477 1.867-2.386 2.418-.909.551-1.896.827-2.96.827-.713 0-1.353-.118-1.921-.355-.568-.237-1.051-.572-1.449-1.004-.398-.433-.702-.961-.914-1.584-.212-.623-.318-1.321-.318-2.094v-7.479h-1.271c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h2.619c.351 0 .602.077.751.232.15.155.225.428.225.819v8.298c0 .443.052.847.155 1.213.103.366.258.68.465.943.207.263.467.466.782.61.315.144.684.216 1.108.216.661 0 1.291-.144 1.89-.433.599-.288 1.126-.69 1.58-1.205.455-.515.816-1.128 1.085-1.839.269-.711.403-1.489.403-2.333v-4.42h-2.2c-.351 0-.602-.077-.751-.232-.15-.155-.225-.428-.225-.819 0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h3.548c.351 0 .602.077.751.232.15.155.225.428.225.819v11.126h1.271zm-30.835 5.362c.713.299 1.462.518 2.247.657.785.139 1.555.209 2.309.209.692 0 1.294-.09 1.805-.27.511-.18.935-.438 1.271-.773.336-.335.586-.734.751-1.198.165-.464.248-.979.248-1.545v-3.183c-.62.773-1.335 1.368-2.146 1.785-.811.417-1.733.626-2.766.626-.961 0-1.849-.162-2.665-.487-.816-.325-1.521-.791-2.115-1.399-.594-.608-1.061-1.35-1.402-2.225-.341-.876-.511-1.87-.511-2.982 0-1.113.17-2.107.511-2.982.341-.876.808-1.617 1.402-2.225.594-.608 1.299-1.074 2.115-1.399.816-.325 1.704-.487 2.665-.487 1.033 0 1.976.229 2.828.688.852.458 1.599 1.105 2.239 1.939v-1.236c0-.391.075-.664.225-.819.15-.155.4-.232.751-.232h2.464c.351 0 .602.077.751.232.15.155.225.428.225.819 0 .391-.075.664-.225.819-.15.155-.4.232-.751.232h-1.271v12.718c0 .927-.142 1.754-.426 2.48-.284.726-.7 1.339-1.247 1.839-.547.5-1.219.883-2.014 1.151-.795.268-1.699.402-2.712.402-.899 0-1.803-.077-2.712-.232-.909-.155-1.772-.386-2.588-.695-.279-.113-.462-.283-.55-.51-.088-.227-.065-.536.07-.927.134-.391.307-.649.519-.773.212-.124.447-.129.705-.015zm8.631-10.786c0-.762-.119-1.442-.356-2.04-.238-.598-.568-1.1-.992-1.507-.424-.407-.927-.719-1.511-.935-.584-.216-1.216-.325-1.898-.325-.702 0-1.327.118-1.875.355-.547.237-1.007.569-1.379.997-.372.428-.656.935-.852 1.522-.196.587-.294 1.231-.294 1.932 0 .701.098 1.344.294 1.932.196.587.48 1.095.852 1.522.372.428.832.76 1.379.997s1.172.355 1.875.355c.682 0 1.314-.108 1.898-.325.584-.216 1.087-.528 1.511-.935.424-.407.754-.909.992-1.507.238-.598.356-1.277.356-2.04zm-48.225 6.861c0 .361-.085.618-.256.773-.17.155-.473.232-.906.232-.434 0-.736-.077-.906-.232-.17-.155-.256-.412-.256-.773v-3.709c0-.361.085-.618.256-.773.17-.155.473-.232.906-.232.227 0 .403.052.527.155.124.103.227.263.31.479.382.999 1.007 1.723 1.875 2.171.868.448 2.019.672 3.455.672 1.24 0 2.169-.219 2.789-.657.62-.438.93-1.012.93-1.723 0-.371-.119-.667-.356-.889-.238-.221-.558-.399-.961-.533-.455-.155-.981-.268-1.58-.34-.599-.072-1.229-.144-1.89-.216-.661-.072-1.32-.165-1.976-.278-.656-.113-1.263-.278-1.821-.495-.351-.134-.671-.299-.961-.495-.289-.196-.54-.428-.751-.695-.212-.268-.377-.577-.496-.927-.119-.35-.178-.752-.178-1.205 0-.69.139-1.301.418-1.831.279-.531.664-.976 1.154-1.337.491-.361 1.069-.634 1.735-.819.666-.185 1.392-.278 2.177-.278 1.033 0 1.96.152 2.781.456.821.304 1.526.719 2.115 1.244v-.695c0-.361.085-.618.256-.773.17-.155.473-.232.906-.232.434 0 .736.077.906.232.17.155.256.412.256.773v2.936c0 .361-.085.618-.256.773-.17.155-.473.232-.906.232-.351 0-.599-.134-.744-.402-.238-.443-.524-.814-.86-1.113-.336-.299-.723-.536-1.162-.711-.439-.175-.922-.299-1.449-.371-.527-.072-1.09-.108-1.689-.108-1.002 0-1.784.175-2.347.525-.563.35-.844.85-.844 1.499 0 .34.111.613.333.819.222.206.529.371.922.495.434.144.94.25 1.518.317.578.067 1.188.134 1.828.201.64.067 1.286.149 1.937.247s1.255.25 1.813.456c.382.144.733.317 1.054.518.32.201.597.443.829.726.232.283.413.613.542.989.129.376.194.811.194 1.306 0 .69-.132 1.319-.395 1.885-.263.567-.651 1.053-1.162 1.46-.511.407-1.141.721-1.89.943-.749.221-1.604.332-2.564.332-1.126 0-2.11-.155-2.952-.464-.842-.309-1.578-.778-2.208-1.406v.865zm-15.722 0c0 .361-.085.618-.256.773-.17.155-.473.232-.906.232-.434 0-.736-.077-.906-.232-.17-.155-.256-.412-.256-.773v-3.709c0-.361.085-.618.256-.773.17-.155.473-.232.906-.232.227 0 .403.052.527.155.124.103.227.263.31.479.382.999 1.007 1.723 1.875 2.171.868.448 2.019.672 3.455.672 1.24 0 2.169-.219 2.789-.657.62-.438.93-1.012.93-1.723 0-.371-.119-.667-.356-.889-.238-.221-.558-.399-.961-.533-.455-.155-.981-.268-1.58-.34-.599-.072-1.229-.144-1.89-.216-.661-.072-1.32-.165-1.976-.278-.656-.113-1.263-.278-1.821-.495-.351-.134-.671-.299-.961-.495-.289-.196-.54-.428-.751-.695-.212-.268-.377-.577-.496-.927-.119-.35-.178-.752-.178-1.205 0-.69.139-1.301.418-1.831.279-.531.664-.976 1.154-1.337.491-.361 1.069-.634 1.735-.819.666-.185 1.392-.278 2.177-.278 1.033 0 1.96.152 2.781.456.821.304 1.526.719 2.115 1.244v-.695c0-.361.085-.618.256-.773.17-.155.473-.232.906-.232.434 0 .736.077.906.232.17.155.256.412.256.773v2.936c0 .361-.085.618-.256.773-.17.155-.473.232-.906.232-.351 0-.599-.134-.744-.402-.238-.443-.524-.814-.86-1.113-.336-.299-.723-.536-1.162-.711-.439-.175-.922-.299-1.449-.371-.527-.072-1.09-.108-1.689-.108-1.002 0-1.784.175-2.347.525-.563.35-.844.85-.844 1.499 0 .34.111.613.333.819.222.206.529.371.922.495.434.144.94.25 1.518.317.578.067 1.188.134 1.828.201.64.067 1.286.149 1.937.247s1.255.25 1.813.456c.382.144.733.317 1.054.518.32.201.597.443.829.726.232.283.413.613.542.989.129.376.194.811.194 1.306 0 .69-.132 1.319-.395 1.885-.263.567-.651 1.053-1.162 1.46-.511.407-1.141.721-1.89.943-.749.221-1.604.332-2.564.332-1.126 0-2.11-.155-2.952-.464-.842-.309-1.578-.778-2.208-1.406v.865zm-7.221-8.468c0-.464-.093-.891-.279-1.283-.186-.391-.462-.729-.829-1.012-.367-.283-.819-.505-1.356-.664-.537-.16-1.162-.24-1.875-.24-.754 0-1.449.129-2.084.386-.635.258-1.18.618-1.635 1.082-.455.464-.811 1.012-1.069 1.646-.258.634-.387 1.326-.387 2.078 0 .752.119 1.445.356 2.078.238.634.576 1.182 1.015 1.646.439.464.968.824 1.588 1.082.62.258 1.307.386 2.061.386.95 0 1.87-.144 2.758-.433.888-.288 1.704-.716 2.448-1.283.269-.206.522-.283.759-.232.238.052.465.258.682.618.176.278.25.567.225.865-.026.299-.189.556-.488.773-.837.618-1.813 1.102-2.929 1.453-1.116.35-2.267.525-3.455.525-1.136 0-2.164-.188-3.083-.564-.919-.376-1.704-.899-2.355-1.569-.651-.67-1.152-1.46-1.503-2.372-.351-.912-.527-1.903-.527-2.975 0-1.071.181-2.063.542-2.975.362-.912.87-1.702 1.526-2.372.656-.67 1.441-1.192 2.355-1.569.914-.376 1.929-.564 3.045-.564.94 0 1.792.167 2.557.502.764.335 1.41.811 1.937 1.429v-.927c0-.361.085-.618.256-.773.17-.155.473-.232.906-.232.434 0 .736.077.906.232.17.155.256.412.256.773v4.481c0 .361-.085.618-.256.773-.17.155-.473.232-.906.232-.434 0-.736-.077-.906-.232-.17-.155-.256-.412-.256-.773z" class="logo__character"/></g></svg> </div> </div> </header> <div class="wrapper"> <h1 class="hide">CSS Guidelines</h1> <h2 class="alpha site-title">High-level advice and guidelines for writing sane, manageable, scalable CSS</h2> <script src="https://cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=cssguidelines" defer="" id="_carbonads_js"></script> <h2 id="about-the-author">About the Author</h2> <p><cite>CSS Guidelines</cite> is a document by me, <a href="https://csswizardry.com/work/">Harry Roberts</a>. I am a Consultant Front-end Architect from the UK, and I help companies all over the world write and manage better quality UIs for their products and teams. I am available for hire.</p> <p class="text-center"> <a href="https://twitter.com/csswizardry" class="btn btn--secondary"><span class="hide-palm">Follow me on </span>Twitter</a> or <a href="https://csswizardry.com/work/" class="btn">Hire<span class="hide-palm"> Me</span></a> </p> <hr /> <h2 id="support-the-guidelines">Support the Guidelines</h2> <p><cite>CSS Guidelines</cite> is provided through a pay-what-you-like model—from $0 upward. If <cite>CSS Guidelines</cite> is useful to you or your team, please consider <a href="https://gumroad.com/l/JAgjq">supporting it</a>.</p> <p class="text-center"> <a href="https://gumroad.com/l/JAgjq" class="btn">Support the Guidelines</a> </p> <p>Get updates about changes, additions, and new and upcoming sections by following <a href="https://twitter.com/cssguidelines">@cssguidelines</a> on Twitter.</p> <hr /> <h2 id="contents">Contents</h2> <ul> <li><a href="#introduction">Introduction</a> <ul> <li><a href="#the-importance-of-a-styleguide">The Importance of a Styleguide</a></li> <li><a href="#disclaimers">Disclaimers</a></li> </ul> </li> <li><a href="#syntax-and-formatting">Syntax and Formatting</a> <ul> <li><a href="#multiple-files">Multiple Files</a></li> <li><a href="#table-of-contents">Table of Contents</a></li> <li><a href="#80-characters-wide">80 Characters Wide</a></li> <li><a href="#titling">Titling</a></li> <li><a href="#anatomy-of-a-ruleset">Anatomy of a Ruleset</a></li> <li><a href="#multi-line-css">Multi-line CSS</a></li> <li><a href="#indenting">Indenting</a> <ul> <li><a href="#indenting-sass">Indenting Sass</a></li> <li><a href="#alignment">Alignment</a></li> </ul> </li> <li><a href="#meaningful-whitespace">Meaningful Whitespace</a></li> <li><a href="#html">HTML</a></li> </ul> </li> <li><a href="#commenting">Commenting</a> <ul> <li><a href="#high-level">High-level</a> <ul> <li><a href="#objectextension-pointers">Object–Extension Pointers</a></li> </ul> </li> <li><a href="#low-level">Low-level</a></li> <li><a href="#preprocessor-comments">Preprocessor Comments</a></li> <li><a href="#removing-comments">Removing Comments</a></li> </ul> </li> <li><a href="#naming-conventions">Naming Conventions</a> <ul> <li><a href="#hyphen-delimited">Hyphen Delimited</a></li> <li><a href="#bem-like-naming">BEM-like Naming</a> <ul> <li><a href="#starting-context">Starting Context</a></li> <li><a href="#more-layers">More Layers</a></li> <li><a href="#modifying-elements">Modifying Elements</a></li> </ul> </li> <li><a href="#naming-conventions-in-html">Naming Conventions in HTML</a></li> <li><a href="#javascript-hooks">JavaScript Hooks</a> <ul> <li><a href="#data--attributes"><code class="language-plaintext highlighter-rouge">data-*</code> Attributes</a></li> </ul> </li> <li><a href="#taking-it-further">Taking It Further</a></li> </ul> </li> <li><a href="#css-selectors">CSS Selectors</a> <ul> <li><a href="#selector-intent">Selector Intent</a></li> <li><a href="#reusability">Reusability</a></li> <li><a href="#location-independence">Location Independence</a></li> <li><a href="#portability">Portability</a> <ul> <li><a href="#quasi-qualified-selectors">Quasi-Qualified Selectors</a></li> </ul> </li> <li><a href="#naming">Naming</a> <ul> <li><a href="#naming-ui-components">Naming UI Components</a></li> </ul> </li> <li><a href="#selector-performance">Selector Performance</a> <ul> <li><a href="#the-key-selector">The Key Selector</a></li> </ul> </li> <li><a href="#general-rules">General Rules</a></li> </ul> </li> <li><a href="#specificity">Specificity</a> <ul> <li><a href="#ids-in-css">IDs in CSS</a></li> <li><a href="#nesting">Nesting</a></li> <li><a href="#important"><code class="language-plaintext highlighter-rouge">!important</code></a></li> <li><a href="#hacking-specificity">Hacking Specificity</a></li> </ul> </li> <li><a href="#architectural-principles">Architectural Principles</a> <ul> <li><a href="#high-level-overview">High-level Overview</a></li> <li><a href="#object-orientation">Object-orientation</a></li> <li><a href="#the-single-responsibility-principle">The Single Responsibility Principle</a></li> <li><a href="#the-openclosed-principle">The Open/Closed Principle</a></li> <li><a href="#dry">DRY</a></li> <li><a href="#composition-over-inheritance">Composition over Inheritance</a></li> <li><a href="#the-separation-of-concerns">The Separation of Concerns</a> <ul> <li><a href="#misconceptions">Misconceptions</a></li> </ul> </li> </ul> </li> </ul> <h3 id="up-next">Up Next</h3> <ul> <li>Preprocessors</li> <li>Layout</li> <li>Performance</li> <li>Sanity, Simplicity</li> <li>Code Smells</li> <li>Legacy, Hacks, and Technical Debt</li> </ul> <hr /> <h2 id="introduction">Introduction</h2> <p>CSS is not a pretty language. While it is simple to learn and get started with, it soon becomes problematic at any reasonable scale. There isn’t much we can do to change how CSS works, but we can make changes to the way we author and structure it.</p> <p>In working on large, long-running projects, with dozens of developers of differing specialities and abilities, it is important that we all work in a unified way in order to—among other things—</p> <ul> <li>keep stylesheets maintainable;</li> <li>keep code transparent, sane, and readable;</li> <li>keep stylesheets scalable.</li> </ul> <p>There are a variety of techniques we must employ in order to satisfy these goals, and <cite>CSS Guidelines</cite> is a document of recommendations and approaches that will help us to do so.</p> <h3 id="the-importance-of-a-styleguide">The Importance of a Styleguide</h3> <p>A coding styleguide (note, not a visual styleguide) is a valuable tool for teams who</p> <ul> <li>build and maintain products for a reasonable length of time;</li> <li>have developers of differing abilities and specialisms;</li> <li>have a number of different developers working on a product at any given time;</li> <li>on-board new staff regularly;</li> <li>have a number of codebases that developers dip in and out of.</li> </ul> <p>Whilst styleguides are typically more suited to product teams—large codebases on long-lived and evolving projects, with multiple developers contributing over prolonged periods of time—all developers should strive for a degree of standardisation in their code.</p> <p>A good styleguide, when well followed, will</p> <ul> <li>set the standard for code quality across a codebase;</li> <li>promote consistency across codebases;</li> <li>give developers a feeling of familiarity across codebases;</li> <li>increase productivity.</li> </ul> <p>Styleguides should be learned, understood, and implemented at all times on a project which is governed by one, and any deviation must be fully justified.</p> <h3 id="disclaimers">Disclaimers</h3> <p><cite>CSS Guidelines</cite> is <em>a</em> styleguide; it is not <em>the</em> styleguide. It contains methodologies, techniques, and tips that I would firmly recommend to my clients and teams, but your own tastes and circumstances may well be different. Your mileage may vary.</p> <p>These guidelines are opinionated, but they have been repeatedly tried, tested, stressed, refined, broken, reworked, and revisited over a number of years on projects of all sizes.</p> <hr /> <h2 id="syntax-and-formatting">Syntax and Formatting</h2> <p>One of the simplest forms of a styleguide is a set of rules regarding syntax and formatting. Having a standard way of writing (<em>literally</em> writing) CSS means that code will always look and feel familiar to all members of the team.</p> <p>Further, code that looks clean <em>feels</em> clean. It is a much nicer environment to work in, and prompts other team members to maintain the standard of cleanliness that they found. Ugly code sets a bad precedent.</p> <p>At a very high-level, we want</p> <ul> <li>two (2) space indents, no tabs;</li> <li>80 character wide columns;</li> <li>multi-line CSS;</li> <li>meaningful use of whitespace.</li> </ul> <p><span class="highlight" id="did-you-see-this-bit">But, as with anything, the specifics are somewhat irrelevant—consistency is key.</span></p> <h3 id="multiple-files">Multiple Files</h3> <p>With the meteoric rise of preprocessors of late, more often is the case that developers are splitting CSS across multiple files.</p> <p>Even if not using a preprocessor, it is a good idea to split discrete chunks of code into their own files, which are concatenated during a build step.</p> <p>If, for whatever reason, you are not working across multiple files, the next sections might require some bending to fit your setup.</p> <h3 id="table-of-contents">Table of Contents</h3> <p>A table of contents is a fairly substantial maintenance overhead, but the benefits it brings far outweigh any costs. It takes a diligent developer to keep a table of contents up to date, but it is well worth sticking with. An up-to-date table of contents provides a team with a single, canonical catalogue of what is in a CSS project, what it does, and in what order.</p> <p>A simple table of contents will—in order, naturally—simply provide the name of the section and a brief summary of what it is and does, for example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/** * CONTENTS * * SETTINGS * Global...............Globally-available variables and config. * * TOOLS * Mixins...............Useful mixins. * * GENERIC * Normalize.css........A level playing field. * Box-sizing...........Better default `box-sizing`. * * BASE * Headings.............H1–H6 styles. * * OBJECTS * Wrappers.............Wrapping and constraining elements. * * COMPONENTS * Page-head............The main page header. * Page-foot............The main page footer. * Buttons..............Button elements. * * TRUMPS * Text.................Text helpers. */ </code></pre></div></div> <p>Each item maps to a section and/or include.</p> <p>Naturally, this section would be substantially larger on the majority of projects, but hopefully we can see how this section—in the master stylesheet—provides developers with a project-wide view of what is being used where, and why.</p> <h3 id="80-characters-wide">80 Characters Wide</h3> <p>Where possible, limit CSS files’ width to 80 characters. Reasons for this include</p> <ul> <li>the ability to have multiple files open side by side;</li> <li>viewing CSS on sites like GitHub, or in terminal windows;</li> <li>providing a comfortable line length for comments.</li> </ul> <pre><code>/** * I am a long-form comment. I describe, in detail, the CSS that follows. I am * such a long comment that I easily break the 80 character limit, so I am * broken across several lines. */</code></pre> <p>There will be unavoidable exceptions to this rule—such as URLs, or gradient syntax—which shouldn’t be worried about.</p> <h3 id="titling">Titling</h3> <p>Begin every new major section of a CSS project with a title:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/*------------------------------------*\ #SECTION-TITLE \*------------------------------------*/ .selector { } </code></pre></div></div> <p>The title of the section is prefixed with a hash (<code class="language-plaintext highlighter-rouge">#</code>) symbol to allow us to perform more targeted searches (e.g. <code class="language-plaintext highlighter-rouge">grep</code>, etc.): instead of searching for just <kbd>SECTION-TITLE</kbd>—which may yield many results—a more scoped search of <kbd>#SECTION-TITLE</kbd> should return only the section in question.</p> <p>Leave a carriage return between this title and the next line of code (be that a comment, some Sass, or some CSS).</p> <p>If you are working on a project where each section is its own file, this title should appear at the top of each one. If you are working on a project with multiple sections per file, each title should be preceded by five (5) carriage returns. This extra whitespace coupled with a title makes new sections much easier to spot when scrolling through large files:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/*------------------------------------*\ #A-SECTION \*------------------------------------*/ .selector { } /*------------------------------------*\ #ANOTHER-SECTION \*------------------------------------*/ /** * Comment */ .another-selector { } </code></pre></div></div> <h3 id="anatomy-of-a-ruleset">Anatomy of a Ruleset</h3> <p>Before we discuss how we write out our rulesets, let’s first familiarise ourselves with the relevant terminology:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[selector] { [property]: [value]; [<--declaration--->] } </code></pre></div></div> <p>For example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.foo, .foo--bar, .baz { display: block; background-color: green; color: red; } </code></pre></div></div> <p>Here you can see we have</p> <ul> <li>related selectors on the same line; unrelated selectors on new lines;</li> <li>a space before our opening brace (<code class="language-plaintext highlighter-rouge">{</code>);</li> <li>properties and values on the same line;</li> <li>a space after our property–value delimiting colon (<code class="language-plaintext highlighter-rouge">:</code>);</li> <li>each declaration on its own new line;</li> <li>the opening brace (<code class="language-plaintext highlighter-rouge">{</code>) on the same line as our last selector;</li> <li>our first declaration on a new line after our opening brace (<code class="language-plaintext highlighter-rouge">{</code>);</li> <li>our closing brace (<code class="language-plaintext highlighter-rouge">}</code>) on its own new line;</li> <li>each declaration indented by two (2) spaces;</li> <li>a trailing semi-colon (<code class="language-plaintext highlighter-rouge">;</code>) on our last declaration.</li> </ul> <p>This format seems to be the largely universal standard (except for variations in number of spaces, with a lot of developers preferring two (2)).</p> <p>As such, the following would be incorrect:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.foo, .foo--bar, .baz { display:block; background-color:green; color:red } </code></pre></div></div> <p>Problems here include</p> <ul> <li>tabs instead of spaces;</li> <li>unrelated selectors on the same line;</li> <li>the opening brace (<code class="language-plaintext highlighter-rouge">{</code>) on its own line;</li> <li>the closing brace (<code class="language-plaintext highlighter-rouge">}</code>) does not sit on its own line;</li> <li>the trailing (and, admittedly, optional) semi-colon (<code class="language-plaintext highlighter-rouge">;</code>) is missing;</li> <li>no spaces after colons (<code class="language-plaintext highlighter-rouge">:</code>).</li> </ul> <h3 id="multi-line-css">Multi-line CSS</h3> <p>CSS should be written across multiple lines, except in very specific circumstances. There are a number of benefits to this:</p> <ul> <li>A reduced chance of merge conflicts, because each piece of functionality exists on its own line.</li> <li>More ‘truthful’ and reliable <code class="language-plaintext highlighter-rouge">diff</code>s, because one line only ever carries one change.</li> </ul> <p>Exceptions to this rule should be fairly apparent, such as similar rulesets that only carry one declaration each, for example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.icon { display: inline-block; width: 16px; height: 16px; background-image: url(/img/sprite.svg); } .icon--home { background-position: 0 0 ; } .icon--person { background-position: -16px 0 ; } .icon--files { background-position: 0 -16px; } .icon--settings { background-position: -16px -16px; } </code></pre></div></div> <p>These types of ruleset benefit from being single-lined because</p> <ul> <li>they still conform to the one-reason-to-change-per-line rule;</li> <li>they share enough similarities that they don’t need to be read as thoroughly as other rulesets—there is more benefit in being able to scan their selectors, which are of more interest to us in these cases.</li> </ul> <h3 id="indenting">Indenting</h3> <p>As well as indenting individual declarations, indent entire related rulesets to signal their relation to one another, for example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.foo { } .foo__bar { } .foo__baz { } </code></pre></div></div> <p>By doing this, a developer can see at a glance that <code class="language-plaintext highlighter-rouge">.foo__baz {}</code> lives inside <code class="language-plaintext highlighter-rouge">.foo__bar {}</code> lives inside <code class="language-plaintext highlighter-rouge">.foo {}</code>.</p> <p>This quasi-replication of the DOM tells developers a lot about where classes are expected to be used without them having to refer to a snippet of HTML.</p> <h4 id="indenting-sass">Indenting Sass</h4> <p>Sass provides nesting functionality. That is to say, by writing this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.foo { color: red; .bar { color: blue; } } </code></pre></div></div> <p>…we will be left with this compiled CSS:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.foo { color: red; } .foo .bar { color: blue; } </code></pre></div></div> <p>When indenting Sass, we stick to the same two (2) spaces, and we also leave a blank line before and after the nested ruleset.</p> <p><strong>N.B.</strong> Nesting in Sass should be avoided wherever possible. See <a href="#specificity">the Specificity section</a> for more details.</p> <h4 id="alignment">Alignment</h4> <p>Attempt to align common and related identical strings in declarations, for example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.foo { -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .bar { position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin-right: -10px; margin-left: -10px; padding-right: 10px; padding-left: 10px; } </code></pre></div></div> <p>This makes life a little easier for developers whose text editors support column editing, allowing them to change several identical and aligned lines in one go.</p> <div class="box box--promo box--outdent"> <p>It looks like you’re enjoying these guidelines…</p> <p><a href="https://gumroad.com/l/JAgjq" class="btn btn--full btn--tertiary">Support Them</a></p> </div> <h3 id="meaningful-whitespace">Meaningful Whitespace</h3> <p>As well as indentation, we can provide a lot of information through liberal and judicious use of whitespace between rulesets. We use:</p> <ul> <li>One (1) empty line between closely related rulesets.</li> <li>Two (2) empty lines between loosely related rulesets.</li> <li>Five (5) empty lines between entirely new sections.</li> </ul> <p>For example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/*------------------------------------*\ #FOO \*------------------------------------*/ .foo { } .foo__bar { } .foo--baz { } /*------------------------------------*\ #BAR \*------------------------------------*/ .bar { } .bar__baz { } .bar__foo { } </code></pre></div></div> <p>There should never be a scenario in which two rulesets do not have an empty line between them. This would be incorrect:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.foo { } .foo__bar { } .foo--baz { } </code></pre></div></div> <h3 id="html">HTML</h3> <p>Given HTML and CSS’ inherently interconnected nature, it would be remiss of me to not cover some syntax and formatting guidelines for markup.</p> <p>Always quote attributes, even if they would work without. This reduces the chance of accidents, and is a more familiar format to the majority of developers. For all this would work (and is valid):</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><div class=box> </code></pre></div></div> <p>…this format is preferred:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><div class="box"> </code></pre></div></div> <p>The quotes are not required here, but err on the safe side and include them.</p> <p>When writing multiple values in a class attribute, separate them with two spaces, thus:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><div class="foo bar"> </code></pre></div></div> <p>When multiple classes are related to each other, consider grouping them in square brackets (<code class="language-plaintext highlighter-rouge">[</code> and <code class="language-plaintext highlighter-rouge">]</code>), like so:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><div class="[ box box--highlight ] [ bio bio--long ]"> </code></pre></div></div> <p>This is not a firm recommendation, and is something I am still trialling myself, but it does carry a number of benefits. Read more in <a href="https://csswizardry.com/2014/05/grouping-related-classes-in-your-markup/"><cite>Grouping related classes in your markup</cite></a>.</p> <p>As with our rulesets, it is possible to use meaningful whitespace in your HTML. You can denote thematic breaks in content with five (5) empty lines, for example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><header class="page-head"> ... </header> <main class="page-content"> ... </main> <footer class="page-foot"> ... </footer> </code></pre></div></div> <p>Separate independent but loosely related snippets of markup with a single empty line, for example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><ul class="primary-nav"> <li class="primary-nav__item"> <a href="/" class="primary-nav__link">Home</a> </li> <li class="primary-nav__item primary-nav__trigger"> <a href="/about" class="primary-nav__link">About</a> <ul class="primary-nav__sub-nav"> <li><a href="/about/products">Products</a></li> <li><a href="/about/company">Company</a></li> </ul> </li> <li class="primary-nav__item"> <a href="/contact" class="primary-nav__link">Contact</a> </li> </ul> </code></pre></div></div> <p>This allows developers to spot separate parts of the DOM at a glance, and also allows certain text editors—like Vim, for example—to manipulate empty-line-delimited blocks of markup.</p> <h3 id="further-reading">Further Reading</h3> <ul> <li><a href="https://csswizardry.com/2014/05/grouping-related-classes-in-your-markup/"><cite>Grouping related classes in your markup</cite></a></li> </ul> <hr /> <h2 id="commenting">Commenting</h2> <p>The cognitive overhead of working with CSS is huge. With so much to be aware of, and so many project-specific nuances to remember, the worst situation most developers find themselves in is being the-person-who-didn’t-write-this-code. Remembering your own classes, rules, objects, and helpers is manageable <em>to an extent</em>, but anyone inheriting CSS barely stands a chance.</p> <p><strong>CSS needs more comments.</strong></p> <p>As CSS is something of a declarative language that doesn’t really leave much of a paper-trail, it is often hard to discern—from looking at the CSS alone—</p> <ul> <li>whether some CSS relies on other code elsewhere;</li> <li>what effect changing some code will have elsewhere;</li> <li>where else some CSS might be used;</li> <li>what styles something might inherit (intentionally or otherwise);</li> <li>what styles something might pass on (intentionally or otherwise);</li> <li>where the author intended a piece of CSS to be used.</li> </ul> <p>This doesn’t even take into account some of CSS’ many quirks—such as various sates of <code class="language-plaintext highlighter-rouge">overflow</code> triggering block formatting context, or certain transform properties triggering hardware acceleration—that make it even more baffling to developers inheriting projects.</p> <p>As a result of CSS not telling its own story very well, it is a language that really does benefit from being heavily commented.</p> <p>As a rule, you should comment anything that isn’t immediately obvious from the code alone. That is to say, there is no need to tell someone that <code class="language-plaintext highlighter-rouge">color: red;</code> will make something red, but if you’re using <code class="language-plaintext highlighter-rouge">overflow: hidden;</code> to clear floats—as opposed to clipping an element’s overflow—this is probably something worth documenting.</p> <h3 id="high-level">High-level</h3> <p>For large comments that document entire sections or components, we use a DocBlock-esque multi-line comment which adheres to our 80 column width.</p> <p>Here is a real-life example from the CSS which styles the page header on <a href="https://csswizardry.com/">CSS Wizardry</a>:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/** * The site’s main page-head can have two different states: * * 1) Regular page-head with no backgrounds or extra treatments; it just * contains the logo and nav. * 2) A masthead that has a fluid-height (becoming fixed after a certain point) * which has a large background image, and some supporting text. * * The regular page-head is incredibly simple, but the masthead version has some * slightly intermingled dependency with the wrapper that lives inside it. */ </code></pre></div></div> <p>This level of detail should be the norm for all non-trivial code—descriptions of states, permutations, conditions, and treatments.</p> <h4 id="objectextension-pointers">Object–Extension Pointers</h4> <p>When working across multiple partials, or in an OOCSS manner, you will often find that rulesets that can work in conjunction with each other are not always in the same file or location. For example, you may have a generic button object—which provides purely structural styles—which is to be extended in a component-level partial which will add cosmetics. We document this relationship across files with simple <i>object–extension pointers</i>. In the object file:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/** * Extend `.btn {}` in _components.buttons.scss. */ .btn { } </code></pre></div></div> <p>And in your theme file:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/** * These rules extend `.btn {}` in _objects.buttons.scss. */ .btn--positive { } .btn--negative { } </code></pre></div></div> <p>This simple, low effort commenting can make a lot of difference to developers who are unaware of relationships across projects, or who are wanting to know how, why, and where other styles might be being inherited from.</p> <h3 id="low-level">Low-level</h3> <p>Oftentimes we want to comment on specific declarations (i.e. lines) in a ruleset. To do this we use a kind of reverse footnote. Here is a more complex comment detailing the larger site headers mentioned above:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/** * Large site headers act more like mastheads. They have a faux-fluid-height * which is controlled by the wrapping element inside it. * * 1. Mastheads will typically have dark backgrounds, so we need to make sure * the contrast is okay. This value is subject to change as the background * image changes. * 2. We need to delegate a lot of the masthead’s layout to its wrapper element * rather than the masthead itself: it is to this wrapper that most things * are positioned. * 3. The wrapper needs positioning context for us to lay our nav and masthead * text in. * 4. Faux-fluid-height technique: simply create the illusion of fluid height by * creating space via a percentage padding, and then position everything over * the top of that. This percentage gives us a 16:9 ratio. * 5. When the viewport is at 758px wide, our 16:9 ratio means that the masthead * is currently rendered at 480px high. Let’s… * 6. …seamlessly snip off the fluid feature at this height, and… * 7. …fix the height at 480px. This means that we should see no jumps in height * as the masthead moves from fluid to fixed. This actual value takes into * account the padding and the top border on the header itself. */ .page-head--masthead { margin-bottom: 0; background: url(/img/css/masthead.jpg) center center #2e2620; @include vendor(background-size, cover); color: $color-masthead; /* [1] */ border-top-color: $color-masthead; border-bottom-width: 0; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1) inset; @include media-query(lap-and-up) { background-image: url(/img/css/masthead-medium.jpg); } @include media-query(desk) { background-image: url(/img/css/masthead-large.jpg); } > .wrapper { /* [2] */ position: relative; /* [3] */ padding-top: 56.25%; /* [4] */ @media screen and (min-width: 758px) { /* [5] */ padding-top: 0; /* [6] */ height: $header-max-height - double($spacing-unit) - $header-border-width; /* [7] */ } } } </code></pre></div></div> <p>These types of comment allow us to keep all of our documentation in one place whilst referring to the parts of the ruleset to which they belong.</p> <h3 id="preprocessor-comments">Preprocessor Comments</h3> <p>With most—if not all—preprocessors, we have the option to write comments that will not get compiled out into our resulting CSS file. As a rule, use these comments to document code that would not get written out to that CSS file either. If you are documenting code which will get compiled, use comments that will compile also. For example, this is correct:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Dimensions of the @2x image sprite: $sprite-width: 920px; $sprite-height: 212px; /** * 1. Default icon size is 16px. * 2. Squash down the retina sprite to display at the correct size. */ .sprite { width: 16px; /* [1] */ height: 16px; /* [1] */ background-image: url(/img/sprites/main.png); background-size: ($sprite-width / 2 ) ($sprite-height / 2); /* [2] */ } </code></pre></div></div> <p>We have documented variables—code which will not get compiled into our CSS file—with preprocessor comments, whereas our CSS—code which will get compiled into our CSS file—is documented using CSS comments. This means that we have only the correct and relevant information available to us when debugging our compiled stylesheets.</p> <h3 id="removing-comments">Removing Comments</h3> <p>It should go without saying that no comments should make their way into production environments—all CSS should be minified, resulting in loss of comments, before being deployed.</p> <hr /> <h2 id="naming-conventions">Naming Conventions</h2> <p>Naming conventions in CSS are hugely useful in making your code more strict, more transparent, and more informative.</p> <p>A good naming convention will tell you and your team</p> <ul> <li>what type of thing a class does;</li> <li>where a class can be used;</li> <li>what (else) a class might be related to.</li> </ul> <p>The naming convention I follow is very simple: hyphen (<code class="language-plaintext highlighter-rouge">-</code>) delimited strings, with BEM-like naming for more complex pieces of code.</p> <p>It’s worth noting that a naming convention is not normally useful CSS-side of development; they really come into their own when viewed in HTML.</p> <h3 id="hyphen-delimited">Hyphen Delimited</h3> <p>All strings in classes are delimited with a hyphen (<code class="language-plaintext highlighter-rouge">-</code>), like so:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.page-head { } .sub-content { } </code></pre></div></div> <p>Camel case and underscores are not used for regular classes; the following are incorrect:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.pageHead { } .sub_content { } </code></pre></div></div> <h3 id="bem-like-naming">BEM-like Naming</h3> <p>For larger, more interrelated pieces of UI that require a number of classes, we use a BEM-like naming convention.</p> <p><cite>BEM</cite>, meaning <i>Block</i>, <i>Element</i>, <i>Modifier</i>, is a front-end methodology coined by developers working at Yandex. Whilst BEM is a complete methodology, here we are only concerned with its naming convention. Further, the naming convention here only is BEM-<em>like</em>; the principles are exactly the same, but the actual syntax differs slightly.</p> <p>BEM splits components’ classes into three groups:</p> <ul> <li>Block: The sole root of the component.</li> <li>Element: A component part of the Block.</li> <li>Modifier: A variant or extension of the Block.</li> </ul> <p>To take an analogy (note, not an example):</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.person { } .person__head { } .person--tall { } </code></pre></div></div> <p>Elements are delimited with two (2) underscores (<code class="language-plaintext highlighter-rouge">__</code>), and Modifiers are delimited by two (2) hyphens (<code class="language-plaintext highlighter-rouge">--</code>).</p> <p>Here we can see that <code class="language-plaintext highlighter-rouge">.person {}</code> is the Block; it is the sole root of a discrete entity. <code class="language-plaintext highlighter-rouge">.person__head {}</code> is an Element; it is a smaller part of the <code class="language-plaintext highlighter-rouge">.person {}</code> Block. Finally, <code class="language-plaintext highlighter-rouge">.person--tall {}</code> is a Modifier; it is a specific variant of the <code class="language-plaintext highlighter-rouge">.person {}</code> Block.</p> <h4 id="starting-context">Starting Context</h4> <p>Your Block context starts at the most logical, self-contained, discrete location. To continue with our person-based analogy, we’d not have a class like <code class="language-plaintext highlighter-rouge">.room__person {}</code>, as the room is another, much higher context. We’d probably have separate Blocks, like so:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.room { } .room__door { } .room--kitchen { } .person { } .person__head { } </code></pre></div></div> <p>If we did want to denote a <code class="language-plaintext highlighter-rouge">.person {}</code> inside a <code class="language-plaintext highlighter-rouge">.room {}</code>, it is more correct to use a selector like <code class="language-plaintext highlighter-rouge">.room .person {}</code> which bridges two Blocks than it is to increase the scope of existing Blocks and Elements.</p> <p>A more realistic example of properly scoped blocks might look something like this, where each chunk of code represents its own Block:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.page { } .content { } .sub-content { } .footer { } .footer__copyright { } </code></pre></div></div> <p>Incorrect notation for this would be:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.page { } .page__content { } .page__sub-content { } .page__footer { } .page__copyright { } </code></pre></div></div> <p>It is important to know when BEM scope starts and stops. As a rule, BEM applies to self-contained, discrete parts of the UI.</p> <div class="box box--promo box--outdent"> <p>Something you need some more help with?</p> <p><a href="http://csswizardry.com/work/" class="btn btn--full btn--tertiary">Hire me</a></p> </div> <h4 id="more-layers">More Layers</h4> <p>If we were to add another Element—called, let’s say, <code class="language-plaintext highlighter-rouge">.person__eye {}</code>—to this <code class="language-plaintext highlighter-rouge">.person {}</code> component, we would not need to step through every layer of the DOM. That is to say, the correct notation would be <code class="language-plaintext highlighter-rouge">.person__eye {}</code>, and not <code class="language-plaintext highlighter-rouge">.person__head__eye {}</code>. Your classes do not reflect the full paper-trail of the DOM.</p> <h4 id="modifying-elements">Modifying Elements</h4> <p>You can have variants of Elements, and these can be denoted in a number of ways depending on how and why they are being modified. Carrying on with our person example, a blue eye might look like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.person__eye--blue { } </code></pre></div></div> <p>Here we can see we’re directly modifying the eye Element.</p> <p>Things can get more complex, however. Please excuse the crude analogy, and let’s imagine we have a face Element that is handsome. The person themselves isn’t that handsome, so we modify the face Element directly—a handsome face on a regular person:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.person__face--handsome { } </code></pre></div></div> <p>But what if that person <em>is</em> handsome, and we want to style their face because of that fact? A regular face on a handsome person:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.person--handsome .person__face { } </code></pre></div></div> <p>Here is one of a few occasions where we’d use a descendant selector to modify an Element based on a Modifier on the Block.</p> <p>If using Sass, we would likely write this like so:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.person { } .person__face { .person--handsome & { } } .person--handsome { } </code></pre></div></div> <p>Note that we do not nest a new instance of <code class="language-plaintext highlighter-rouge">.person__face {}</code> inside of <code class="language-plaintext highlighter-rouge">.person--handsome {}</code>; instead, we make use of Sass’ parent selectors to prepend <code class="language-plaintext highlighter-rouge">.person--handsome</code> onto the existing <code class="language-plaintext highlighter-rouge">.person__face {}</code> selector. This means that all of our <code class="language-plaintext highlighter-rouge">.person__face {}</code>-related rules exist in one place, and aren’t spread throughout the file. This is general good practice when dealing with nested code: keep all of your context (e.g. all <code class="language-plaintext highlighter-rouge">.person__face {}</code> code) encapsulated in one location.</p> <h3 id="naming-conventions-in-html">Naming Conventions in HTML</h3> <p>As I previously hinted at, naming conventions aren’t necessarily all that useful in your CSS. Where naming conventions’ power really lies is in your markup. Take the following, non-naming-conventioned HTML:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><div class="box profile pro-user"> <img class="avatar image" /> <p class="bio">...</p> </div> </code></pre></div></div> <p>How are the classes <code class="language-plaintext highlighter-rouge">box</code> and <code class="language-plaintext highlighter-rouge">profile</code> related to each other? How are the classes <code class="language-plaintext highlighter-rouge">profile</code> and <code class="language-plaintext highlighter-rouge">avatar</code> related to each other? Are they related at all? Should you be using <code class="language-plaintext highlighter-rouge">pro-user</code> alongside <code class="language-plaintext highlighter-rouge">bio</code>? Will the classes <code class="language-plaintext highlighter-rouge">image</code> and <code class="language-plaintext highlighter-rouge">profile</code> live in the same part of the CSS? Can you use <code class="language-plaintext highlighter-rouge">avatar</code> anywhere else?</p> <p>From that markup alone, it is very hard to answer any of those questions. Using a naming convention, however, changes all that:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><div class="box profile profile--is-pro-user"> <img class="avatar profile__image" /> <p class="profile__bio">...</p> </div> </code></pre></div></div> <p>Now we can clearly see which classes are and are not related to each other, and how; we know what classes we can’t use outside of the scope of this component; and we know which classes we may be free to reuse elsewhere.</p> <h3 id="javascript-hooks">JavaScript Hooks</h3> <p>As a rule, it is unwise to bind your CSS and your JS onto the same class in your HTML. This is because doing so means you can’t have (or remove) one without (removing) the other. It is much cleaner, much more transparent, and much more maintainable to bind your JS onto specific classes.</p> <p>I have known occasions before when trying to refactor some CSS has unwittingly removed JS functionality because the two were tied to each other—it was impossible to have one without the other.</p> <p>Typically, these are classes that are prepended with <code class="language-plaintext highlighter-rouge">js-</code>, for example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><input type="submit" class="btn js-btn" value="Follow" /> </code></pre></div></div> <p>This means that we can have an element elsewhere which can carry with style of <code class="language-plaintext highlighter-rouge">.btn {}</code>, but without the behaviour of <code class="language-plaintext highlighter-rouge">.js-btn</code>.</p> <h4 id="data--attributes"><code class="language-plaintext highlighter-rouge">data-*</code> Attributes</h4> <p>A common practice is to use <code class="language-plaintext highlighter-rouge">data-*</code> attributes as JS hooks, but this is incorrect. <code class="language-plaintext highlighter-rouge">data-*</code> attributes, as per the spec, are used <q><strong>to store custom data</strong> private to the page or application</q> (emphasis mine). <code class="language-plaintext highlighter-rouge">data-*</code> attributes are designed to store data, not be bound to.</p> <h3 id="taking-it-further">Taking It Further</h3> <p>As previously mentioned, these are very simple naming conventions, and ones that don’t do much more than denote three distinct groups of class.</p> <p>I would encourage you to read up on and further look in to your naming convention in order to provide more functionality—I know it’s something I’m keen to research and investigate further.</p> <h3 id="further-reading-1">Further Reading</h3> <ul> <li><a href="https://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/"><cite>MindBEMding – getting your head ’round BEM syntax</cite></a></li> </ul> <hr /> <h2 id="css-selectors">CSS Selectors</h2> <p>Perhaps somewhat surprisingly, one of the most fundamental, critical aspects of writing maintainable and scalable CSS is selectors. Their specificity, their portability, and their reusability all have a direct impact on the mileage we will get out of our CSS, and the headaches it might bring us.</p> <h3 id="selector-intent">Selector Intent</h3> <p>It is important when writing CSS that we scope our selectors correctly, and that we’re selecting the right things for the right reasons. <i>Selector Intent</i> is the process of deciding and defining what you want to style and how you will go about selecting it. For example, if you are wanting to style your website’s main navigation menu, a selector like this would be incredibly unwise:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>header ul { } </code></pre></div></div> <p>This selector’s intent is to style any <code class="language-plaintext highlighter-rouge">ul</code> inside any <code class="language-plaintext highlighter-rouge">header</code> element, whereas <em>our</em> intent was to style the site’s main navigation. This is poor Selector Intent: you can have any number of <code class="language-plaintext highlighter-rouge">header</code> elements on a page, and they in turn can house any number of <code class="language-plaintext highlighter-rouge">ul</code>s, so a selector like this runs the risk of applying very specific styling to a very wide number of elements. This will result in having to write more CSS to undo the greedy nature of such a selector.</p> <p>A better approach would be a selector like:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.site-nav { } </code></pre></div></div> <p>An unambiguous, explicit selector with good Selector Intent. We are explicitly selecting the right thing for exactly the right reason.</p> <p>Poor Selector Intent is one of the biggest reasons for headaches on CSS projects. Writing rules that are far too greedy—and that apply very specific treatments via very far reaching selectors—causes unexpected side effects and leads to very tangled stylesheets, with selectors overstepping their intentions and impacting and interfering with otherwise unrelated rulesets.</p> <p>CSS cannot be encapsulated, it is inherently leaky, but we can mitigate some of these effects by not writing such globally-operating selectors: <strong>your selectors should be as explicit and well reasoned as your reason for wanting to select something.</strong></p> <h3 id="reusability">Reusability</h3> <p>With a move toward a more component-based approach to constructing UIs, the idea of reusability is paramount. We want the option to be able to move, recycle, duplicate, and syndicate components across our projects.</p> <p>To this end, we make heavy use of classes. IDs, as well as being hugely over-specific, cannot be used more than once on any given page, whereas classes can be reused an infinite amount of times. Everything you choose, from the type of selector to its name, should lend itself toward being reused.</p> <h3 id="location-independence">Location Independence</h3> <p>Given the ever-changing nature of most UI projects, and the move to more component-based architectures, it is in our interests not to style things based on where they are, but on <em>what</em> they are. That is to say, our components’ styling should not be reliant upon where we place them—they should remain entirely location independent.</p> <p>Let’s take an example of a call-to-action button that we have chosen to style via the following selector:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.promo a { } </code></pre></div></div> <p>Not only does this have poor Selector Intent—it will greedily style any and every link inside of a <code class="language-plaintext highlighter-rouge">.promo</code> to look like a button—it is also pretty wasteful as a result of being so locationally dependent: we can’t reuse that button with its correct styling outside of <code class="language-plaintext highlighter-rouge">.promo</code> because it is explicitly tied to that location. A far better selector would have been:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.btn { } </code></pre></div></div> <p>This single class can be reused anywhere outside of <code class="language-plaintext highlighter-rouge">.promo</code> and will always carry its correct styling. As a result of a better selector, this piece of UI is more portable, more recyclable, doesn’t have any dependencies, and has much better Selector Intent. <strong>A component shouldn’t have to live in a certain place to look a certain way.</strong></p> <h3 id="portability">Portability</h3> <p>Reducing, or, ideally, removing, location dependence means that we can move components around our markup more freely, but how about improving our ability to move classes around components? On a much lower level, there are changes we can make to our selectors that make the selectors themselves—as opposed to the components they create—more portable. Take the following example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>input.btn { } </code></pre></div></div> <p>This is a <i>qualified</i> selector; the leading <code class="language-plaintext highlighter-rouge">input</code> ties this ruleset to only being able to work on <code class="language-plaintext highlighter-rouge">input</code> elements. By omitting this qualification, we allow ourselves to reuse the <code class="language-plaintext highlighter-rouge">.btn</code> class on any element we choose, like an <code class="language-plaintext highlighter-rouge">a</code>, for example, or a <code class="language-plaintext highlighter-rouge">button</code>.</p> <p>Qualified selectors do not lend themselves well to being reused, and every selector we write should be authored with reuse in mind.</p> <p>Of course, there are times when you may want to legitimately qualify a selector—you might need to apply some very specific styling to a particular element when it carries a certain class, for example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/** * Embolden and colour any element with a class of `.error`. */ .error { color: red; font-weight: bold; } /** * If the element is a `div`, also give it some box-like styling. */ div.error { padding: 10px; border: 1px solid; } </code></pre></div></div> <p>This is one example where a qualified selector might be justifiable, but I would still recommend an approach more like:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/** * Text-level errors. */ .error-text { color: red; font-weight: bold; } /** * Elements that contain errors. */ .error-box { padding: 10px; border: 1px solid; } </code></pre></div></div> <p>This means that we can apply <code class="language-plaintext highlighter-rouge">.error-box</code> to any element, and not just a <code class="language-plaintext highlighter-rouge">div</code>—it is more reusable than a qualified selector.</p> <h4 id="quasi-qualified-selectors">Quasi-Qualified Selectors</h4> <p>One thing that qualified selectors can be useful for is signalling where a class might be expected or intended to be used, for example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ul.nav { } </code></pre></div></div> <p>Here we can see that the <code class="language-plaintext highlighter-rouge">.nav</code> class is meant to be used on a <code class="language-plaintext highlighter-rouge">ul</code> element, and not on a <code class="language-plaintext highlighter-rouge">nav</code>. By using <i>quasi-qualified selectors</i> we can still provide that information without actually qualifying the selector:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/*ul*/.nav { } </code></pre></div></div> <p>By commenting out the leading element, we can still leave it to be read, but avoid qualifying and increasing the specificity of the selector.</p> <h3 id="naming">Naming</h3> <p>As Phil Karlton once said, <q>There are only two hard things in Computer Science: cache invalidation and naming things.</q></p> <p>I won’t comment on the former claim here, but the latter has plagued me for years. My advice with regard to naming things in CSS is to pick a name that is sensible, but somewhat ambiguous: aim for high reusability. For example, instead of a class like <code class="language-plaintext highlighter-rouge">.site-nav</code>, choose something like <code class="language-plaintext highlighter-rouge">.primary-nav</code>; rather than <code class="language-plaintext highlighter-rouge">.footer-links</code>, favour a class like <code class="language-plaintext highlighter-rouge">.sub-links</code>.</p> <p>The differences in these names is that the first of each two examples is tied to a very specific use case: they can only be used as the site’s navigation or the footer’s links respectively. By using slightly more ambiguous names, we can increase our ability to reuse these components in different circumstances.</p> <p>To quote Nicolas Gallagher:</p> <blockquote> <p>Tying your class name semantics tightly to the nature of the content has already reduced the ability of your architecture to scale or be easily put to use by other developers.</p> </blockquote> <p>That is to say, we should use sensible names—classes like <code class="language-plaintext highlighter-rouge">.border</code> or <code class="language-plaintext highlighter-rouge">.red</code> are never advisable—but we should avoid using classes which describe the exact nature of the content and/or its use cases. <strong>Using a class name to describe content is redundant because content describes itself.</strong></p> <p>The debate surrounding semantics has raged for years, but it is important that we adopt a more pragmatic, sensible approach to naming things in order to work more efficiently and effectively. Instead of focussing on ‘semantics’, look more closely at sensibility and longevity—choose names based on ease of maintenance, not for their perceived meaning.</p> <p>Name things for people; they’re the only things that actually <em>read</em> your classes (everything else merely matches them). Once again, it is better to strive for reusable, recyclable classes rather than writing for specific use cases. Let’s take an example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/** * Runs the risk of becoming out of date; not very maintainable. */ .blue { color: blue; } /** * Depends on location in order to be rendered properly. */ .header span { color: blue; } /** * Too specific; limits our ability to reuse. */ .header-color { color: blue; } /** * Nicely abstracted, very portable, doesn’t risk becoming out of date. */ .highlight-color { color: blue; } </code></pre></div></div> <p>It is important to strike a balance between names that do not literally describe the style that the class brings, but also ones that do not explicitly describe specific use cases. Instead of <code class="language-plaintext highlighter-rouge">.home-page-panel</code>, choose <code class="language-plaintext highlighter-rouge">.masthead</code>; instead of <code class="language-plaintext highlighter-rouge">.site-nav</code>, favour <code class="language-plaintext highlighter-rouge">.primary-nav</code>; instead of <code class="language-plaintext highlighter-rouge">.btn-login</code>, opt for <code class="language-plaintext highlighter-rouge">.btn-primary</code>.</p> <h4 id="naming-ui-components">Naming UI Components</h4> <p>Naming components with agnosticism and reusability in mind really helps developers construct and modify UIs much more quickly, and with far less waste. However, it can sometimes be beneficial to provide more specific or meaningful naming alongside the more ambiguous class, particularly when several agnostic classes come together to form a more complex and specific component that might benefit from having a more meaningful name. In this scenario, we augment the classes with a <code class="language-plaintext highlighter-rouge">data-ui-component</code> attribute which houses a more specific name, for example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><ul class="tabbed-nav" data-ui-component="Main Nav"> </code></pre></div></div> <p>Here we have the benefits of a highly reusable class name which does not describe—and, therefore, tie itself to—a specific use case, and added meaning via our <code class="language-plaintext highlighter-rouge">data-ui-component</code> attribute. The <code class="language-plaintext highlighter-rouge">data-ui-component</code>’s value can take any format you wish, like title case:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><ul class="tabbed-nav" data-ui-component="Main Nav"> </code></pre></div></div> <p>Or class-like:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><ul class="tabbed-nav" data-ui-component="main-nav"> </code></pre></div></div> <p>Or namespaced:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><ul class="tabbed-nav" data-ui-component="nav-main"> </code></pre></div></div> <p>The implementation is largely personal preference, but the concept still remains: <strong>Add any useful or specific meaning via a mechanism that will not inhibit your and your team’s ability to recycle and reuse CSS.</strong></p> <div class="box box--promo box--outdent"> <p>It looks like you’re enjoying these guidelines…</p> <p><a href="https://gumroad.com/l/JAgjq" class="btn btn--full btn--tertiary">Support Them</a></p> </div> <h3 id="selector-performance">Selector Performance</h3> <p>A topic which is—with the quality of today’s browsers—more interesting than it is important, is selector performance. That is to say, how quickly a browser can match the selectors your write in CSS up with the nodes it finds in the DOM.</p> <p>Generally speaking, the longer a selector is (i.e. the more component parts) the slower it is, for example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>body.home div.header ul { } </code></pre></div></div> <p>…is a far less efficient selector than:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.primary-nav { } </code></pre></div></div> <p>This is because browsers read CSS selectors <strong>right-to-left</strong>. A browser will read the first selector as</p> <ul> <li>find all <code class="language-plaintext highlighter-rouge">ul</code> elements in the DOM;</li> <li>now check if they live anywhere inside an element with a class of <code class="language-plaintext highlighter-rouge">.header</code>;</li> <li>next check that <code class="language-plaintext highlighter-rouge">.header</code> class exists on a <code class="language-plaintext highlighter-rouge">div</code> element;</li> <li>now check that that all lives anywhere inside any elements with a class of <code class="language-plaintext highlighter-rouge">.home</code>;</li> <li>finally, check that <code class="language-plaintext highlighter-rouge">.home</code> exists on a <code class="language-plaintext highlighter-rouge">body</code> element.</li> </ul> <p>The second, in contrast, is simply a case of the browser reading</p> <ul> <li>find all the elements with a class of <code class="language-plaintext highlighter-rouge">.primary-nav</code>.</li> </ul> <p>To further compound the problem, we are using descendant selectors (e.g. <code class="language-plaintext highlighter-rouge">.foo .bar {}</code>). The upshot of this is that a browser is required to start with the rightmost part of the selector (i.e. <code class="language-plaintext highlighter-rouge">.bar</code>) and keep looking up the DOM indefinitely until it finds the next part (i.e. <code class="language-plaintext highlighter-rouge">.foo</code>). This could mean stepping up the DOM dozens of times until a match is found.</p> <p>This is just one reason why <strong>nesting with preprocessors is often a false economy</strong>; as well as making selectors unnecessarily more specific, and creating location dependency, it also creates more work for the browser.</p> <p>By using a child selector (e.g. <code class="language-plaintext highlighter-rouge">.foo > .bar {}</code>) we can make the process much more efficient, because this only requires the browser to look one level higher in the DOM, and it will stop regardless of whether or not it found a match.</p> <h4 id="the-key-selector">The Key Selector</h4> <p>Because browsers read selectors right-to-left, the rightmost selector is often critical in defining a selector’s performance: this is called the <i>key selector</i>.</p> <p>The following selector might appear to be highly performant at first glance. It uses an ID which is nice and fast, and there can only ever be one on a page, so surely this will be a nice and speedy lookup—just find that one ID and then style everything inside of it:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#foo * { } </code></pre></div></div> <p>The problem with this selector is that the key selector (<code class="language-plaintext highlighter-rouge">*</code>) is very, <em>very</em> far reaching. What this selector actually does is find <em>every single</em> node in the DOM (even <code class="language-plaintext highlighter-rouge"><title></code>, <code class="language-plaintext highlighter-rouge"><link></code>, and <code class="language-plaintext highlighter-rouge"><head></code> elements; <em>everything</em>) and then looks to see if it lives anywhere at any level within <code class="language-plaintext highlighter-rouge">#foo</code>. This is a very, <em>very</em> expensive selector, and should most likely be avoided or rewritten.</p> <p>Thankfully, by writing selectors with good <a href="#selector-intent">Selector Intent</a>, we are probably avoiding inefficient selectors by default; we are very unlikely to have greedy key selectors if we’re targeting the right things for the right reason.</p> <p>That said, however, CSS selector performance should be fairly low on your list of things to optimise; browsers are fast, and are only ever getting faster, and it is only on notable edge cases that inefficient selectors would be likely to pose a problem.</p> <p>As well as their own specific issues, nesting, qualifying, and poor Selector Intent all contribute to less efficient selectors.</p> <h3 id="general-rules">General Rules</h3> <p>Your selectors are fundamental to writing good CSS. To very briefly sum up the above sections:</p> <ul> <li><strong>Select what you want explicitly</strong>, rather than relying on circumstance or coincidence. Good Selector Intent will rein in the reach and leak of your styles.</li> <li><strong>Write selectors for reusability</strong>, so that you can work more efficiently and reduce waste and repetition.</li> <li><strong>Do not nest selectors unnecessarily</strong>, because this will increase specificity and affect where else you can use your styles.</li> <li><strong>Do not qualify selectors unnecessarily</strong>, as this will impact the number of different elements you can apply styles to.</li> <li><strong>Keep selectors as short as possible</strong>, in order to keep specificity down and performance up.</li> </ul> <p>Focussing on these points will keep your selectors a lot more sane and easy to work with on changing and long-running projects.</p> <h3 id="further-reading-2">Further Reading</h3> <ul> <li><a href="https://csswizardry.com/2012/07/shoot-to-kill-css-selector-intent/"><cite>Shoot to kill; CSS selector intent</cite></a></li> <li><a href="https://csswizardry.com/2013/05/scope-in-css/"><cite>‘Scope’ in CSS</cite></a></li> <li><a href="https://csswizardry.com/2012/05/keep-your-css-selectors-short/"><cite>Keep your CSS selectors short</cite></a></li> <li><a href="https://nicolasgallagher.com/about-html-semantics-front-end-architecture/"><cite>About HTML semantics and front-end architecture</cite></a></li> <li><a href="https://csswizardry.com/2014/03/naming-ui-components-in-oocss/"><cite>Naming UI components in OOCSS</cite></a></li> <li><a href="https://csswizardry.com/2011/09/writing-efficient-css-selectors/"><cite>Writing efficient CSS selectors</cite></a></li> </ul> <hr /> <h2 id="specificity">Specificity</h2> <p>As we’ve seen, CSS isn’t the most friendly of languages: globally operating, very leaky, dependent on location, hard to encapsulate, based on inheritance… But! None of that even comes close to the horrors of specificity.</p> <p>No matter how well considered your naming, regardless of how perfect your source order and cascade are managed, and how well you’ve scoped your rulesets, just one overly-specific selector can undo everything. It is a gigantic curveball, and undermines CSS’ very nature of the cascade, inheritance, and source order.</p> <p>The problem with specificity is that it sets precedents and trumps that cannot <em>simply</em> be undone. If we take a real example that I was responsible for some years ago:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#content table { } </code></pre></div></div> <p>Not only does this exhibit poor <a href="#selector-intent">Selector Intent</a>—I didn’t actually want every <code class="language-plaintext highlighter-rouge">table</code> in the <code class="language-plaintext highlighter-rouge">#content</code> area, I wanted a specific type of <code class="language-plaintext highlighter-rouge">table</code> that just happened to live there—it is a hugely over-specific selector. This became apparent a number of weeks later, when I needed a second type of <code class="language-plaintext highlighter-rouge">table</code>:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#content table { } /** * Uh oh! My styles get overwritten by `#content table {}`. */ .my-new-table { } </code></pre></div></div> <p>The first selector was trumping the specificity of the one defined <em>after</em> it, working against CSS’ source-order based application of styles. In order to remedy this, I had two main options. I could</p> <ol> <li>refactor my CSS and HTML to remove that ID;</li> <li>write a more specific selector to override it.</li> </ol> <p>Unfortunately, refactoring would have taken a long time; it was a mature product and the knock-on effects of removing this ID would have been a more substantial business cost than the second option: just write a more specific selector.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#content table { } #content .my-new-table { } </code></pre></div></div> <p>Now I have a selector that is <em>even more specific still!</em> And if I ever want to override this one, I will need another selector of at least the same specificity defined after it. I’ve started on a downward spiral.</p> <p>Specificity can, among other things,</p> <ul> <li>limit your ability to extend and manipulate a codebase;</li> <li>interrupt and undo CSS’ cascading, inheriting nature;</li> <li>cause avoidable verbosity in your project;</li> <li>prevent things from working as expected when moved into different environments;</li> <li>lead to serious developer frustration.</li> </ul> <p>All of these issues are greatly magnified when working on a larger project with a number of developers contributing code.</p> <h3 id="keep-it-low-at-all-times">Keep It Low at All Times</h3> <p>The problem with specificity isn’t necessarily that it’s high or low; it’s the fact it is so variant and that it cannot be opted out of: the only way to deal with it is to get progressively more specific—the notorious <i>specificity wars</i> we looked at above.</p> <p>One of the single, simplest tips for an easier life when writing CSS—particularly at any reasonable scale—is to keep always try and keep specificity as low as possible at all times. Try to make sure there isn’t a lot of variance between selectors in your codebase, and that all selectors strive for as low a specificity as possible.</p> <p>Doing so will instantly help you tame and manage your project, meaning that no overly-specific selectors are likely to impact or affect anything of a lower specificity elsewhere. It also means you’re less likely to need to fight your way out of specificity corners, and you’ll probably also be writing much smaller stylesheets.</p> <p>Simple changes to the way we work include, but are not limited to,</p> <ul> <li>not using IDs in your CSS;</li> <li>not nesting selectors;</li> <li>not qualifying classes;</li> <li>not chaining selectors.</li> </ul> <p><strong>Specificity can be wrangled and understood, but it is safer just to avoid it entirely.</strong></p> <h3 id="ids-in-css">IDs in CSS</h3> <p>If we want to keep specificity low, which we do, we have one really quick-win, simple, easy-to-follow rule that we can employ to help us: avoid using IDs in CSS.</p> <p>Not only are IDs inherently non-reusable, they are also vastly more specific than any other selector, and therefore become specificity anomalies. Where the rest of your selectors are relatively low specificity, your ID-based selectors are, comparatively, much, <em>much</em> higher.</p> <p>In fact, to highlight the severity of this difference, see how <em>one thousand</em> chained classes cannot override the specificity of a single ID: <a href="http://jsfiddle.net/csswizardry/0yb7rque/">jsfiddle.net/0yb7rque</a>. <small>(Please note that in Firefox you may see the text rendering in blue: this is a <a href="https://twitter.com/codepo8/status/505004085398224896">known bug</a>, and an ID will be overridden by 256 chained classes.)</small></p> <p><small><strong>N.B.</strong> It is still perfectly okay to use IDs in HTML and JavaScript; it is only in CSS that they prove troublesome.</small></p> <p>It is often suggested that developers who choose not to use IDs in CSS merely <q>don’t understand how specificity works</q>. This is as incorrect as it is offensive: no matter how experienced a developer you are, this behaviour cannot be circumvented; no amount of knowledge will make an ID less specific.</p> <p>Opting into this way of working only introduces the chance of problems occurring further down the line, and—particularly when working at scale—all efforts should be made to <em>avoid</em> the potential for problems to arise. In a sentence:</p> <p><strong>It is just not worth introducing the risk.</strong></p> <h3 id="nesting">Nesting</h3> <p>We’ve already looked at how nesting can lead to location dependent and potentially inefficient code, but now it’s time to take a look at another of its pitfalls: it makes selectors more specific.</p> <p>When we talk about nesting, we don’t necessarily mean preprocessor nesting, like so:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.foo { .bar { } } </code></pre></div></div> <p>We’re actually talking about <em>descendant</em> or <em>child</em> selectors; selectors which rely on a thing within a thing. That could look like any one of the following:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/** * An element with a class of `.bar` anywhere inside an element with a class of * `.foo`. */ .foo .bar { } /** * An element with a class of `.module-title` directly inside an element with a * class of `.module`. */ .module > .module-title { } /** * Any `li` element anywhere inside a `ul` element anywhere inside a `nav` * element */ nav ul li { } </code></pre></div></div> <p>Whether you arrive at this CSS via a preprocessor or not isn’t particularly important, but it is worth noting that <strong>preprocessors tout this as a feature, where is actually to be avoided wherever possible</strong>.</p> <p>Generally speaking, each part in a compound selector adds specificity. Ergo, the fewer parts to a compound selector then the lower its overall specificity, and we always want to keep specificity low. To quote Jonathan Snook:</p> <blockquote> <p>…whenever declaring your styles, <strong>use the least number of selectors required to style an element.</strong></p> </blockquote> <p>Let’s look at an example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.widget { padding: 10px; } .widget > .widget__title { color: red; } </code></pre></div></div> <p>To style an element with a class of <code class="language-plaintext highlighter-rouge">.widget__title</code>, we have a selector that is twice as specific as it needs to be. That means that if we want to make any modifications to <code class="language-plaintext highlighter-rouge">.widget__title</code>, we’ll need another at-least-equally specific selector:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.widget { ... } .widget > .widget__title { ... } .widget > .widget__title--sub { color: blue; } </code></pre></div></div> <p>Not only is this entirely avoidable—we caused this problem ourselves—we have a selector that is literally double the specificity it needs to be. We used 200% of the specificity actually required. And not only <em>that</em>, but this also leads to needless verbosity in our code—more to send over the wire.</p> <p>As a rule, <strong>if a selector will work without it being nested then do not nest it</strong>.</p> <h4 id="scope">Scope</h4> <p>One possible advantage of nesting—which, unfortunately, does not outweigh the disadvantages of increased specificity—is that it provides us with a namespace of sorts. A selector like <code class="language-plaintext highlighter-rouge">.widget .title</code> scopes the styling of <code class="language-plaintext highlighter-rouge">.title</code> to an element that only exists inside of an element carrying a class of <code class="language-plaintext highlighter-rouge">.widget</code>.</p> <p>This goes some way to providing our CSS with scope and encapsulation, but does still mean that our selectors are twice as specific as they need to be. A better way of providing this scope would be via a namespace—which we already have in the form of <a href="#bem-like-naming">BEM-like Naming</a>—which does not lead to an unnecessary increase in specificity.</p> <p>Now we have better scoped CSS with minimal specificity—the best of both worlds.</p> <h5 id="further-reading-3">Further Reading</h5> <ul> <li><a href="https://csswizardry.com/2013/05/scope-in-css/"><cite>‘Scope’ in CSS</cite></a></li> </ul> <h3 id="important"><code class="language-plaintext highlighter-rouge">!important</code></h3> <p>The word <code class="language-plaintext highlighter-rouge">!important</code> sends shivers down the spines of almost all front-end developers. <code class="language-plaintext highlighter-rouge">!important</code> is a direct manifestation of problems with specificity; it is a way of cheating your way out of specificity wars, but usually comes at a heavy price. It is often viewed as a last resort—a desperate, defeated stab at patching over the symptoms of a much bigger problem with your code.</p> <p>The general rule is that <code class="language-plaintext highlighter-rouge">!important</code> is always a bad thing, but, to quote Jamie Mason:</p> <blockquote> <p>Rules are the children of principles.</p> </blockquote> <p>That is to say, a single rule is a simple, black-and-white way of adhering to a much larger principle. When you’re starting out, the rule <q>never use <code class="language-plaintext highlighter-rouge">!important</code></q> is a good one.</p> <p>However, once you begin to grow and mature as a developer, you begin to understand that the principle behind that rule is simply about keeping specificity low. You’ll also learn when and where the rules can be bent…</p> <p><code class="language-plaintext highlighter-rouge">!important</code> does have a place in CSS projects, but only if used sparingly and proactively.</p> <p>Proactive use of <code class="language-plaintext highlighter-rouge">!important</code> is when it is used <em>before</em> you’ve encountered any specificity problems; when it is used as a guarantee rather than as a fix. For example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.one-half { width: 50% !important; } .hidden { display: none !important; } </code></pre></div></div> <p>These two helper, or <i>utility</i>, classes are very specific in their intentions: you would only use them if you wanted something to be rendered at 50% width or not rendered at all. If you didn’t want this behaviour, you would not use these classes, therefore whenever you do use them you will definitely want them to win.</p> <p>Here we proactively apply <code class="language-plaintext highlighter-rouge">!important</code> to ensure that these styles always win. This is correct use of <code class="language-plaintext highlighter-rouge">!important</code> to guarantee that these trumps always work, and don’t accidentally get overridden by something else more specific.</p> <p>Incorrect, <i>reactive</i> use of <code class="language-plaintext highlighter-rouge">!important</code> is when it is used to combat specificity problems after the fact: applying <code class="language-plaintext highlighter-rouge">!important</code> to declarations because of poorly architected CSS. For example, let’s imagine we have this HTML:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><div class="content"> <h2 class="heading-sub">...</h2> </div> </code></pre></div></div> <p>…and this CSS:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.content h2 { font-size: 2em; } .heading-sub { font-size: 1.5em !important; } </code></pre></div></div> <p>Here we can see how we’ve used <code class="language-plaintext highlighter-rouge">!important</code> to force our <code class="language-plaintext highlighter-rouge">.heading-sub {}</code> styles to reactively override our <code class="language-plaintext highlighter-rouge">.content h2 {}</code> selector. This could have been circumvented by any number of things, including using better Selector Intent, or avoiding nesting.</p> <p>In these situations, it is preferable that you investigate and refactor any offending rulesets to try and bring specificity down across the board, as opposed to introducing such specificity heavyweights.</p> <p><strong>Only use <code class="language-plaintext highlighter-rouge">!important</code> proactively, not reactively.</strong></p> <h3 id="hacking-specificity">Hacking Specificity</h3> <p>With all that said on the topic of specificity, and keeping it low, it is inevitable that we will encounter problems. No matter how hard we try, and how conscientious we are, there will always be times that we need to hack and wrangle specificity.</p> <p>When these situations do arise, it is important that we handle the hacks as safely and elegantly as possible.</p> <p>In the event that you need to increase the specificity of a class selector, there are a number of options. We could nest the class inside something else to bring its specificity up. For example, we could use <code class="language-plaintext highlighter-rouge">.header .site-nav {}</code> to bring up the specificity of a simple <code class="language-plaintext highlighter-rouge">.site-nav {}</code> selector.</p> <p>The problem with this, as we’ve discussed, is that it introduces location dependency: these styles will only work when the <code class="language-plaintext highlighter-rouge">.site-nav</code> component is in the <code class="language-plaintext highlighter-rouge">.header</code> component.</p> <p>Instead, we can use a much safer hack that will not impact this component’s portability: we can chain that class with itself:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.site-nav.site-nav { } </code></pre></div></div> <p>This chaining doubles the specificity of the selector, but does not introduce any dependency on location.</p> <p>In the event that we do, for whatever reason, have an ID in our markup that we cannot replace with a class, select it via an attribute selector as opposed to an ID selector. For example, let’s imagine we have embedded a third-party widget on our page. We can style the widget via the markup that it outputs, but we have no ability to edit that markup ourselves:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><div id="third-party-widget"> ... </div> </code></pre></div></div> <p>Even though we know not to use IDs in CSS, what other option do we have? We want to style this HTML but have no access to it, and all it has on it is an ID.</p> <p>We do this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[id="third-party-widget"] { } </code></pre></div></div> <p>Here we are selecting based on an attribute rather than an ID, and attribute selectors have the same specificity as a class. This allows us to style based on an ID, but without introducing its specificity.</p> <p>Do keep in mind that these <em>are</em> hacks, and should not be used unless you have no better alternative.</p> <h4 id="further-reading-4">Further Reading</h4> <ul> <li><a href="https://csswizardry.com/2014/07/hacks-for-dealing-with-specificity/"><cite>Hacks for dealing with specificity</cite></a></li> </ul> <hr /> <h2 id="architectural-principles">Architectural Principles</h2> <p>You would be forgiven for thinking that an architecture for CSS is a somewhat grandiose and unnecessary concept: why would something so simple, so <em>straightforward</em>, need something as complex or considered as an architecture?!</p> <p>Well, as we’ve seen, CSS’ simplicity, its looseness, and its unruly nature mean that the best way of managing (read, taming) it at any reasonable scale is through a strict and specific architecture. A solid architecture can help us control our specificity, enforce naming conventions, manage our source order, create a sane development environment, and generally make managing our CSS projects a lot more consistent and comfortable.</p> <p>There is no tool, no preprocessor, no magic bullet, that will make your CSS better on its own: a developer’s best tool when working with such a loose syntax is self-discipline, conscientiousness, and diligence, and a well-defined architecture will help enforce and facilitate these traits.</p> <p>Architectures are large, overarching, principle-led collections of smaller conventions which come together to provide a managed environment in which code is written and maintained. Architectures are typically quite high level, and leave implementation details—such as naming conventions or syntax and formatting, for example—to the team implementing it.</p> <p>Most architectures are usually based around existing design patterns and paradigms, and, more often than not, these paradigms were born of computer scientists and software engineers. For all CSS isn’t ‘code’, and doesn’t exhibit many traits that programming languages do, we find that we can apply some of these same principles to our own work.</p> <p>In this section, we’ll take a look at some of these design patterns and paradigms, and how we can use them to reduce code—and increase code reuse—in our CSS projects.</p> <h3 id="high-level-overview">High-level Overview</h3> <p>At a very high-level, your architecture should help you</p> <ul> <li>provide a consistent and sane environment;</li> <li>accommodate change;</li> <li>grow and scale your codebase;</li> <li>promote reuse and efficiency;</li> <li>increase productivity.</li> </ul> <p>Typically, this will mean a class-based and componentised architecture, split up into manageable modules, probably using a preprocessor. Of course, there is far more to an architecture than that, so let’s look at some principles…</p> <h3 id="object-orientation">Object-orientation</h3> <p><i>Object-orientation</i> is a programming paradigm that breaks larger programs up into smaller, in(ter)dependent objects that all have their own roles and responsibilities. From Wikipedia:</p> <blockquote> <p>Object-oriented programming (OOP) is a programming paradigm that represents the concept of ‘objects’ […] which are usually instances of classes, [and] are used to interact with one another to design applications and computer programs.</p> </blockquote> <p>When applied to CSS, we call it object-oriented CSS, or <i>OOCSS</i>. OOCSS was coined and popularised by Nicole Sullivan, whose <cite>Media Object</cite> has become the poster child of the methodology.</p> <p>OOCSS deals with the separation of UIs into <i>structure</i> and <i>skin</i>: breaking UI components into their underlying structural forms, and layering their cosmetic forms on separately. This means that we can recycle common and recurring design <em>patterns</em> very cheaply without having to necessarily recycle their specific implementation details at the same time. OOCSS promotes reuse of code, which makes us quicker, as well as keeping the size of our codebase down.</p> <p>Structural aspects can be thought of like skeletons; common, recurring frames that provide design-free constructs known as <i>objects</i> and <i>abstractions</i>. Objects and abstractions are simple design patterns that are devoid of any cosmetics; we abstract out the shared structural traits from a series of components into a generic object.</p> <p>Skin is a layer that we (optionally) add to our structure in order to give objects and abstractions a specific look-and-feel. Let’s look at an example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/** * A simple, design-free button object. Extend this object with a `.btn--*` skin * class. */ .btn { display: inline-block; padding: 1em 2em; vertical-align: middle; } /** * Positive buttons’ skin. Extends `.btn`. */ .btn--positive { background-color: green; color: white; } /** * Negative buttons’ skin. Extends `.btn`. */ .btn--negative { background-color: red; color: white; } </code></pre></div></div> <p>Above, we can see how the <code class="language-plaintext highlighter-rouge">.btn {}</code> class simply provides structural styling to an element, and doesn’t concern itself with any cosmetics. We supplement the <code class="language-plaintext highlighter-rouge">.btn {}</code> object with a second class, such as <code class="language-plaintext highlighter-rouge">.btn--negative {}</code> in order to give that DOM node specific cosmetics:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><button class="btn btn--negative">Delete</button> </code></pre></div></div> <p>Favour the multiple-class approach over using something like <code class="language-plaintext highlighter-rouge">@extend</code>: using multiple classes in your markup—as opposed to wrapping the classes up into one using a preprocessor—</p> <ul> <li>gives you a better paper-trail in your markup, and allows you to see quickly and explicitly which classes are acting on a piece of HTML;</li> <li>allows for greater composition in that classes are not tightly bound to other styles in your CSS.</li> </ul> <p>Whenever you are building a UI component, try and see if you can break it into two parts: one for structural styles (paddings, layout, etc.) and another for skin (colours, typefaces, etc.).</p> <h4 id="further-reading-5">Further Reading</h4> <ul> <li><a href="http://www.stubbornella.org/content/2010/06/25/the-media-object-saves-hundreds-of-lines-of-code/">The media object saves hundreds of lines of code</a></li> <li><a href="https://csswizardry.com/2013/05/the-flag-object/">The flag object</a></li> <li><a href="https://csswizardry.com/2014/03/naming-ui-components-in-oocss/">Naming UI components in OOCSS</a></li> </ul> <h3 id="the-single-responsibility-principle">The Single Responsibility Principle</h3> <p>The <i>single responsibility principle</i> is a paradigm that, very loosely, states that all pieces of code (in our case, classes) should focus on doing one thing and one thing only. More formally:</p> <blockquote> <p>…the single responsibility principle states that every context (class, function, variable, etc.) should have a single responsibility, and that responsibility should be entirely encapsulated by the context.</p> </blockquote> <p>What this means for us is that our CSS should be composed of a series of much smaller classes that focus on providing very specific and limited functionality. This means that we need to decompose UIs into their smallest component pieces that each serve a single responsibility; they all do just one job, but can be very easily combined and composed to make much more versatile and complex constructs. Let’s take some example CSS that does not adhere to the single responsibility principle:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.error-message { display: block; padding: 10px; border-top: 1px solid #f00; border-bottom: 1px solid #f00; background-color: #fee; color: #f00; font-weight: bold; } .success-message { display: block; padding: 10px; border-top: 1px solid #0f0; border-bottom: 1px solid #0f0; background-color: #efe; color: #0f0; font-weight: bold; } </code></pre></div></div> <p>Here we can see that—despite being named after one very specific use-case—these classes are handling quite a lot: layout, structure, and cosmetics. We also have a <em>lot</em> of repetition. We need to refactor this in order to abstract out some shared objects (OOCSS) and bring it more inline with the single responsibility principle. We can break these two classes out into four much smaller responsibilities:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.box { display: block; padding: 10px; } .message { border-style: solid; border-width: 1px 0; font-weight: bold; } .message--error { background-color: #fee; color: #f00; } .message--success { background-color: #efe; color: #0f0; } </code></pre></div></div> <p>Now we have a general abstraction for boxes which can live, and be used, completely separately from our message component, and we have a base message component that can be extended by a number of smaller responsibility classes. The amount of repetition has been greatly reduced, and our ability to extend and compose our CSS has been greatly increased. This is a great example of OOCSS and the single responsibility principle working in tandem.</p> <p>By focussing on single responsibilities, we can give our code much more flexibility, and extending components’ functions becomes very simple when sticking to the <i>open/closed principle</i>, which we’re going to look at next.</p> <h4 id="further-reading-6">Further Reading</h4> <ul> <li><a href="https://csswizardry.com/2012/04/the-single-responsibility-principle-applied-to-css/">The single responsibility principle applied to CSS</a></li> </ul> <h3 id="the-openclosed-principle">The Open/Closed Principle</h3> <p>The <i>open/closed principle</i>, in my opinion, is rather poorly named. It is poorly named because 50% of the vital information is omitted from its title. The open/closed principle states that</p> <blockquote> <p>[s]oftware entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.</p> </blockquote> <p>See? The most important words—<i>extension</i> and <i>modification</i>—are completely missing from the name, which isn’t very useful at all.</p> <p>Once you have trained yourself to remember what the words open and closed actually relate to, you’ll find that open/closed principle remarkably simple: any additions, new functionality, or features we add to our classes should be added via <em>extension</em>—we should not modify these classes directly. This really trains us to write bulletproof single responsibilities: because we shouldn’t modify objects and abstractions directly, we need to make sure we get them as simple as possible the first time. This means that we should never need to actually change an abstraction—we’d simply stop using it—but any slight variants of it can be made very easily by extending it.</p> <p>Let’s take an example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.box { display: block; padding: 10px; } .box--large { padding: 20px; } </code></pre></div></div> <p>Here we can see that the <code class="language-plaintext highlighter-rouge">.box {}</code> object is incredibly simple: we’ve stripped it right back into one very small and very focussed responsibility. To modify that box, we extend it with another class; <code class="language-plaintext highlighter-rouge">.box--large {}</code>. Here the <code class="language-plaintext highlighter-rouge">.box {}</code> class is closed to modification, but open to being extended.</p> <p>An incorrect way of achieving the same might look like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.box { display: block; padding: 10px; } .content .box { padding: 20px; } </code></pre></div></div> <p>Not only is this overly specific, locationally dependent, and potentially displaying poor Selector Intent, we are modifying the <code class="language-plaintext highlighter-rouge">.box {}</code> directly. We should rarely—if ever—find an object or abstraction’s class as a key selector in a compound selector.</p> <p>A selector like <code class="language-plaintext highlighter-rouge">.content .box {}</code> is potentially troublesome because</p> <ul> <li>it forces all <code class="language-plaintext highlighter-rouge">.box</code> components into that style when placed inside of <code class="language-plaintext highlighter-rouge">.content</code>, which means the modification is dictated to developers, whereas developers should be allowed to opt into changes explicitly;</li> <li>the <code class="language-plaintext highlighter-rouge">.box</code> style is now unpredictable to developers; the single responsibility no longer exists because nesting the selector produces a forced caveat.</li> </ul> <p>All modifications, additions, and changes should always be opt-in, not mandatory. If you think something might need a slight adjustment to take it away from the norm, provide another class which adds this functionality.</p> <p>When working in a team environment, be sure to write API-like CSS; always ensure that existing classes remain backward compatible (i.e. no changes at their root) and provide new hooks to bring in new features. Changing the root object, abstraction, or component could have huge knock-on effects for developers making use of that code elsewhere, so never modify existing code directly.</p> <p>Exceptions may present themselves when it transpires that a root object does need a rewrite or refactor, but it is only in these specific cases that you should modify code. Remember: <strong>open for extension; closed for modification</strong>.</p> <h4 id="further-reading-7">Further Reading</h4> <ul> <li><a href="https://csswizardry.com/2012/06/the-open-closed-principle-applied-to-css/">The open/closed principle applied to CSS</a></li> </ul> <h3 id="dry">DRY</h3> <p><i>DRY</i>, which stands for <i>Don’t Repeat Repeat Yourself</i>, is a micro-principle used in software development which aims to keep the repetition of key information to a minimum. Its formal definition is that</p> <blockquote> <p>[e]very piece of knowledge must have a single, unambiguous, authoritative representation within a system.</p> </blockquote> <p>Although a very simple principle—in principle—DRY is often misinterpreted as the necessity to never repeat the exact same thing twice at all in a project. This is impractical and usually counterproductive, and can lead to forced abstractions, over-thought and -engineered code, and unusual dependencies.</p> <p>The key isn’t to avoid all repetition, but to normalise and abstract <em>meaningful</em> repetition. If two things happen to share the same declarations coincidentally, then we needn’t DRY anything out; that repetition is purely circumstantial and cannot be shared or abstracted. For example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.btn { display: inline-block; padding: 1em 2em; font-weight: bold; } [...] .page-title { font-size: 3rem; line-height: 1.4; font-weight: bold; } [...] .user-profile__title { font-size: 1.2rem; line-height: 1.5; font-weight: bold; } </code></pre></div></div> <p>From the above code, we can reasonably deduce that the <code class="language-plaintext highlighter-rouge">font-weight: bold;</code> declaration appears three times purely coincidentally. To try and create an abstraction, mixin, or <code class="language-plaintext highlighter-rouge">@extend</code> directive to cater for this repetition would be overkill, and would tie these three rulesets together based purely on circumstance.</p> <p>However, imagine we’re using a web-font that requires <code class="language-plaintext highlighter-rouge">font-weight: bold;</code> to be declared every time the <code class="language-plaintext highlighter-rouge">font-family</code> is:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.btn { display: inline-block; padding: 1em 2em; font-family: "My Web Font", sans-serif; font-weight: bold; } [...] .page-title { font-size: 3rem; line-height: 1.4; font-family: "My Web Font", sans-serif; font-weight: bold; } [...] .user-profile__title { font-size: 1.2rem; line-height: 1.5; font-family: "My Web Font", sans-serif; font-weight: bold; } </code></pre></div></div> <p>Here we’re repeating a more meaningful snippet of CSS; these two declarations have to always be declared together. In this instance, we probably would DRY out our CSS.</p> <p>I would recommend using a mixin over <code class="language-plaintext highlighter-rouge">@extend</code> here because, even though the two declarations are thematically grouped, the rulesets themselves are still separate, unrelated entities: to use <code class="language-plaintext highlighter-rouge">@extend</code> would be to physically group these unrelated rulesets together in our CSS, thus making the unrelated related.</p> <p>Our mixin:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@mixin my-web-font() { font-family: "My Web Font", sans-serif; font-weight: bold; } .btn { display: inline-block; padding: 1em 2em; @include my-web-font(); } [...] .page-title { font-size: 3rem; line-height: 1.4; @include my-web-font(); } [...] .user-profile__title { font-size: 1.2rem; line-height: 1.5; @include my-web-font(); } </code></pre></div></div> <p>Now the two declarations only exist once, meaning we’re not repeating ourselves. If we ever switch out our web-font, or move to a <code class="language-plaintext highlighter-rouge">font-weight: normal;</code> version, we only need to make that change in one place.</p> <p>In short, only DRY code that is actually, thematically related. Do not try to reduce purely coincidental repetition: <strong>duplication is better than the wrong abstraction</strong>.</p> <h4 id="further-reading-8">Further Reading</h4> <ul> <li><a href="https://csswizardry.com/2013/07/writing-dryer-vanilla-css/">Writing DRYer vanilla CSS</a></li> </ul> <h3 id="composition-over-inheritance">Composition over Inheritance</h3> <p>Now that we’re used to spotting abstractions and creating single responsibilities, we should be in a great position to start composing more complex composites from a series of much smaller component parts. Nicole Sullivan likens this to using Lego; tiny, single responsibility pieces which can be combined in a number of different quantities and permutations to create a multitude of very different looking results.</p> <p>This idea of building through composition is not a new one, and is often referred to as <i>composition over inheritance</i>. This principle suggests that larger systems should be composed from much smaller, individual parts, rather than inheriting behaviour from a much larger, monolithic object. This should keep your code decoupled—nothing inherently relies on anything else.</p> <p>Composition is a very valuable principle for an architecture to make use of, particularly considering the move toward component-based UIs. It will mean you can more easily recycle and reuse functionality, as well rapidly construct larger parts of UI from a known set of composable objects. Think back to our error message example in the <a href="#the-single-responsibility-principle">Single Responsibility Principle</a> section; we created a complete UI component by composing a number of much smaller and unrelated objects.</p> <h3 id="the-separation-of-concerns">The Separation of Concerns</h3> <p>The <i>separation of concerns</i> is a principle which, at first, sounds a lot like the single responsibility principle. The separation of concerns states that code should be broken up</p> <blockquote> <p>into distinct sections, such that each section addresses a separate concern. A concern is a set of information that affects the code of a computer program. […] A program that embodies SoC well is called a modular program.</p> </blockquote> <p>Modular is a word we’re probably used to; the idea of breaking UIs and CSS into much smaller, composable pieces. The separation of concerns is just a formal definition which covers the concepts of modularity and encapsulation in code. In CSS this means building individual components, and writing code which only focusses itself on one task at a time.</p> <p>The term was coined by Edsger W. Dijkstra, who rather elegantly said:</p> <blockquote> <p>Let me try to explain to you, what to my taste is characteristic for all intelligent thinking. It is, that one is willing to study in depth an aspect of one’s subject matter in isolation for the sake of its own consistency, all the time knowing that one is occupying oneself only with one of the aspects. We know that a program must be correct and we can study it from that viewpoint only; we also know that it should be efficient and we can study its efficiency on another day, so to speak. In another mood we may ask ourselves whether, and if so: why, the program is desirable. But nothing is gained—on the contrary!—by tackling these various aspects simultaneously. It is what I sometimes have called ‘the separation of concerns’, which, even if not perfectly possible, is yet the only available technique for effective ordering of one’s thoughts, that I know of. This is what I mean by ‘focusing one’s attention upon some aspect’: it does not mean ignoring the other aspects, it is just doing justice to the fact that from this aspect’s point of view, the other is irrelevant. It is being one- and multiple-track minded simultaneously.</p> </blockquote> <p>Beautiful. The idea here is to focus fully on one thing at once; build one thing to do its job very well whilst paying as little attention as possible to other facets of your code. Once you have addressed and built all these separate concerns in isolation—meaning they’re probably very modular, decoupled, and encapsulated—you can begin bringing them together into a larger project.</p> <p>A great example is layout. If you are using a grid system, all of the code pertaining to layout should exist on its own, without including anything else. You’ve written code that handles layout, and that’s it:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><div class="layout"> <div class="layout__item two-thirds"> </div> <div class="layout__item one-third"> </div> </div> </code></pre></div></div> <p>You will now need to write new, separate code to handle what lives inside of that layout:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><div class="layout"> <div class="layout__item two-thirds"> <section class="content"> ... </section> </div> <div class="layout__item one-third"> <section class="sub-content"> ... </section> </div> </div> </code></pre></div></div> <p>The separation of concerns allows you to keep code self-sufficient, ignorant, and ultimately a lot more maintainable. Code which adheres to the separation of concerns can be much more confidently modified, edited, extended, and maintained because we know how far its responsibilities reach. We know that modifying layout, for example, will only ever modify layout—nothing else.</p> <p>The separation of concerns increases reusability and confidence whilst reducing dependency.</p> <h4 id="misconceptions">Misconceptions</h4> <p>There are, I feel, a number of unfortunate misconceptions surrounding the separation of concerns when applied to HTML and CSS. They all seem to revolve around some format of:</p> <blockquote> <p>Using classes for CSS in your markup breaks the separation of concerns.</p> </blockquote> <p>Unfortunately, this is simply not true. The separation of concerns <em>does</em> exist in the context of HTML and CSS (and JS), but not in the way a lot of people seem to believe.</p> <p>The separation of concerns when applied to front-end code is not about classes-in-HTML-purely-for-styling-hooks-blurring-the-lines-between-concerns; it is about the very fact that we are using different languages for markup and styling at all.</p> <p>Back before CSS was widely adopted, we’d use <code class="language-plaintext highlighter-rouge">table</code>s to lay content out, and <code class="language-plaintext highlighter-rouge">font</code> elements with <code class="language-plaintext highlighter-rouge">color</code> attributes to provide cosmetic styling. The problem here is that HTML was being used to create content and also to style it; there was no way of having one without the other. This was a complete lack of separation of concerns, which was a problem. CSS’ job was to provide a completely new syntax to apply this styling, allowing us to separate our content and style concerns across two technologies.</p> <p>Another common argument is that <q>putting classes in your HTML puts style information in your markup</q>.</p> <p>So, in a bid to circumvent this, people adopt selectors that might look a little like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>body > header:first-of-type > nav > ul > li > a { } </code></pre></div></div> <p>This CSS—presumably to style our site’s main nav—has the usual problems of location dependency, poor Selector Intent, and high specificity, but it also manages to do <em>exactly what developers are trying to avoid</em>, only in the opposite direction: <strong>it puts DOM information in your CSS</strong>. Aggressive attempts to avoid putting any style hints or hooks in markup only lead to overloading stylesheets with DOM information.</p> <p>In short: having classes in your markup does not violate the separation of concerns. Classes merely act as an API to link two separate concerns together. The simplest way to separate concerns is to write well formed HTML and well formed CSS, and link to two together with sensible, judicious use of classes.</p> <div class="box box--promo box--outdent"> <p>Something you need some more help with?</p> <p><a href="http://csswizardry.com/work/" class="btn btn--full btn--tertiary">Hire me</a></p> </div> <footer class="page-foot"> <hr class="hr-minor" /> <p class="version">2.2.5</p> <p>Last updated: <time datetime="2022-09-01">1 September, 2022</time></p> <p>© 2017 <a href="https://twitter.com/csswizardry">Harry Roberts</a></p> </footer> </div> <script> if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/sw.js').then(function(registration) { // Successfully registered the Service Worker //console.log('Service Worker registration successful with scope: ', registration.scope); }).catch(function(err) { // Failed to register the Service Worker //console.log('Service Worker registration failed: ', err); }); }); } </script> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-1856861-11', 'auto'); ga('send', 'pageview'); </script> </body> </html>