Help
RSS
API
Feed
Maltego
Contact
Domain > sitewatch.app
×
More information on this domain is in
AlienVault OTX
Is this malicious?
Yes
No
DNS Resolutions
Date
IP Address
2020-09-14
157.230.35.153
(
ClassC
)
2025-12-10
13.52.188.95
(
ClassC
)
Port 443
HTTP/1.1 200 OKAccept-Ranges: bytesAge: 0Cache-Control: public,max-age0,must-revalidateCache-Status: Netlify Edge; fwdmissContent-Length: 262195Content-Type: text/html; charsetUTF-8Date: Wed, 10 Dec 2025 11:20:33 GMTEtag: f04db3dda5296e06abc744639526ecf7-sslServer: NetlifyStrict-Transport-Security: max-age31536000X-Nf-Request-Id: 01KC3ZVM2QFPCEJ774NY1MP5Z4 !doctype html>html data-n-head-ssr langen data-n-head%7B%22lang%22:%7B%22ssr%22:%22en%22%7D%7D> head> title>sitewatch/title>meta data-n-headssr charsetutf-8>meta data-n-headssr nameviewport contentwidthdevice-width,initial-scale1>meta data-n-headssr data-hiddescription namedescription contentSiteWatch.app>meta data-n-headssr data-hidmobile-web-app-capable namemobile-web-app-capable contentyes>meta data-n-headssr data-hidapple-mobile-web-app-title nameapple-mobile-web-app-title contentsitewatch>meta data-n-headssr data-hidauthor nameauthor contentDavid Darke>meta data-n-headssr data-hidtheme-color nametheme-color content#fff>meta data-n-headssr data-hidog:type nameog:type propertyog:type contentwebsite>meta data-n-headssr data-hidog:title nameog:title propertyog:title contentsitewatch>meta data-n-headssr data-hidog:site_name nameog:site_name propertyog:site_name contentsitewatch>meta data-n-headssr data-hidog:description nameog:description propertyog:description contentSiteWatch.app>link data-n-headssr relicon typeimage/x-icon href/favicon.ico>link data-n-headssr relmanifest href/_nuxt/manifest.d0ca4c18.json>link data-n-headssr relshortcut icon href/_nuxt/icons/icon_64.5f6a36.png>link data-n-headssr relapple-touch-icon href/_nuxt/icons/icon_512.5f6a36.png sizes512x512>link relpreload href/_nuxt/7e2805414fd369c0a42a.js asscript>link relpreload href/_nuxt/afa78572961c8cafe1b7.js asscript>link relpreload href/_nuxt/273afb766edb22194650.js asscript>link relpreload href/_nuxt/9a9898ea5b57175815e3.js asscript>style data-vue-ssr-id38dfa7e4:0 3191d5ad:0 932a8f60:0>/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}typebutton,typereset,typesubmit{-webkit-appearance:button}typebutton::-moz-focus-inner,typereset::-moz-focus-inner,typesubmit::-moz-focus-inner{border-style:none;padding:0}typebutton:-moz-focusring,typereset:-moz-focusring,typesubmit:-moz-focusring{outline:1px dotted ButtonText}typecheckbox,typeradio{box-sizing:border-box;padding:0}typenumber::-webkit-inner-spin-button,typenumber::-webkit-outer-spin-button{height:auto}typesearch{-webkit-appearance:textfield;outline-offset:-2px}typesearch::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}hidden,template{display:none}html{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,Helvetica Neue,Arial,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}*,:after,:before{box-sizing:border-box;border:0 solid #e2e8f0}rolebutton{cursor:pointer}.inline-block{display:inline-block}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.nuxt-progress{position:fixed;top:0;left:0;right:0;height:2px;width:0;opacity:1;transition:width .1s,opacity .4s;background-color:#fff;z-index:999999}html{font-family:Source Sans Pro,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:16px;word-spacing:1px;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;box-sizing:border-box}*,:after,:before{box-sizing:border-box;margin:0}.button--green{display:inline-block;border-radius:4px;border:1px solid #3b8070;color:#3b8070;text-decoration:none;padding:10px 30px}.button--green:hover{color:#fff;background-color:#3b8070}.button--grey{display:inline-block;border-radius:4px;border:1px solid #35495e;color:#35495e;text-decoration:none;padding:10px 30px;margin-left:15px}.button--grey:hover{color:#fff;background-color:#35495e}/style> /head> body> div data-server-renderedtrue id__nuxt>!---->div id__layout>div>div classposts>/div>/div>/div>/div>script>window.__NUXT__function(e){return{layout:default,data:{},error:null,state:{posts:{id:303748,slug:animated-matryoshka-dolls-in-css,title:{rendered:Animated Matryoshka Dolls in CSS},excerpt:{rendered:p>Here’s a fun one. How might we create a set of those cool Matryoshka dolls where they nest inside one another… but in CSS? I toyed with this idea in my head for a little while. Then, I saw a tweet from CSS-Tricks and the article image had the dolls. I took that as a …/p>\n,protected:e},date:2020-02-27T08:23:10,tags:743,708,795,content:{rendered:\np>Here’s a fun one. How might we create a set of those cool Matryoshka dolls where they nest inside one another... but in CSS?/p>\n\n\n\np>I toyed with this idea in my head for a little while. Then, I saw a tweet from CSS-Tricks and the article image had the dolls. I took that as a sign! It was time to put fingers to the keyboard./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755002//matryoshka-dolls.png?ssl1 alt classwp-image-296824 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1200/v1582755002//matryoshka-dolls.png 1200w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_848/v1582755002//matryoshka-dolls.png 848w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_579/v1582755002//matryoshka-dolls.png 579w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755002//matryoshka-dolls.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Our goal here is to make these fun and interactive, where we can click on a doll to open it up and reveal another, smaller doll. Oh, and stick with just CSS for the functionality. And while we’re at it, let’s replace the dolls with our own character, say a CodePen bear. Something like this:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755828//beqrs-finalbears-final.gif?ssl1 alt classwp-image-303772 data-recalc-dims1/>/figure>\n\n\n\np>We won\t dwell on making things pretty to start. Let\s get some markup on the page and thrash out the mechanics first./p>\n\n\n\np>We can’t have an infinite amount of dolls. When we reach the innermost doll, it\d be nice to be able to reset the dolls without having to do a page refresh. A neat trick for this is to wrap our scene in an HTML form. That way we can use an input and set the code>type/code> attribute to code>reset/code> to avoid using any JavaScript./p>\n\n\n\npre relHTML classwp-block-csstricks-code-block language-markup data-line>code markuptt><form>\n <input typereset idreset/>\n <label forreset titleReset>Reset</label>\n</form>/code>/pre>\n\n\n\np>Next, we need some dolls. Or bears. Or something to start with. The key here will be to use the classic a hrefhttps://css-tricks.com/the-checkbox-hack/>checkbox hack/a> and any associated form labels. As a note, I’m going to use Pug to handle the markup because it supports loops, making things a little easier. But, you can certainly write the HTML by hand. Here’s the start with form fields and labels that set up the checkbox hack./p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_RwNmPwr src//codepen.io/anon/embed/RwNmPwr?height350&theme-id1&slug-hashRwNmPwr&default-tabresult height350 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed RwNmPwr titleCodePen Embed RwNmPwr classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>Try clicking some of the inputs and hitting the Reset input. They all become unchecked. Nice, we’ll use that./p>\n\n\n\np>We have some interactivity but nothing is really happening yet. Here’s the plan:/p>\n\n\n\nol>li>We’ll only show one checkbox at a time/li>li>Checking a checkbox should reveal the label for the next checkbox./li>li>When we get to the last checkbox, there our only option should be to reset the form./li>/ol>\n\n\n\np>The trick will be to make use of the CSS adjacent sibling combinator (code>+/code>)./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>input:checked + label + input + label {\n display: block;\n}/code>/pre>\n\n\n\np>When a checkbox is checked, we need to show the label for the next doll, which will be three siblings along in the DOM. How do we make the first label visible? Give it an explicit code>display: block/code> via inline styles in our markup. Putting this together, we have something along these lines:/p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_MWYdwjP src//codepen.io/anon/embed/MWYdwjP?height350&theme-id1&slug-hashMWYdwjP&default-tabresult height350 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed MWYdwjP titleCodePen Embed MWYdwjP classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>Clicking each label reveals the next. Hold on, the last label isn’t shown! That’s correct. And that’s because the last label doesn’t have a checkbox. We need to add a rule that caters to that last label./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>input:checked + label + input + label,\ninput:checked + label + label {\n display: block;\n}/code>/pre>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_NWPVqyM src//codepen.io/anon/embed/NWPVqyM?height350&theme-id1&slug-hashNWPVqyM&default-tabresult height350 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed NWPVqyM titleCodePen Embed NWPVqyM classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>Cool. We\re getting somewhere. That\s the basic mechanics. Now things are going to get a little trickier. /p>\n\n\n\nh3>Basic styling/h3>\n\n\n\np>So, you might be thinking, “Why aren’t we hiding the checked label?” Good question! But, if we hide it straight away, we won’t have any transition between the current doll and the next. Before we start animating our dolls, let’s create basic boxes that will represent a doll. We can style them up so they mimic the doll outline without the detail./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.doll {\n color: #fff;\n cursor: pointer;\n height: 200px;\n font-size: 2rem;\n left: 50%;\n position: absolute;\n text-align: center;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 100px;\n}\n\n.doll:nth-of-type(even) {\n background: #00f;\n}\n\n.doll:nth-of-type(odd) {\n background: #f00;\n}/code>/pre>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_oNgRjvZ src//codepen.io/anon/embed/oNgRjvZ?height350&theme-id1&slug-hashoNgRjvZ&default-tabresult height350 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed oNgRjvZ titleCodePen Embed oNgRjvZ classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>Clicking one doll instantly reveals the next one and, when we’ve reached the last doll, we can reset the form to start again. That’s what we want here./p>\n\n\n\nh3>The mechanics/h3>\n\n\n\np>We are going to animate the dolls based on a center point. Our animation will consist of many steps:/p>\n\n\n\nol>li>Slide the current doll out to the left./li>li>Open the doll to reveal the next one./li>li>Move the next doll where the current one started./li>li>Make the current doll fade out./li>li>Assign the next doll as the current doll./li>/ol>\n\n\n\np>Let’s start by sliding the current doll out to the left. We apply an animation when we click a label. Using the code>:checked/code> pseudo-selector we can target the current doll. At this point, it’s worth noting that we are going to use CSS variables to control animation speed and behavior. This will make it easier to chain animations on the labels./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>:root {\n --speed: 0.25;\n --base-slide: 100;\n --slide-distance: 60;\n}\n\ninput:checked + label {\n animation: slideLeft calc(var(--speed) * 1s) forwards;\n}\n\n@keyframes slideLeft {\n to {\n transform: translate(calc((var(--base-slide) * -1px) + var(--slide-distance) * -1%), 0);\n }\n}/code>/pre>\n\n\n\np>That looks great. But there’s an issue. As soon as we click a label, we could click it again and reset the animation. We don\t want that to happen./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/css-tricks.com/wp-content/uploads/2020/02/bears-01.gif?ssl1 alt classwp-image-303763 data-recalc-dims1/>/figure>\n\n\n\np>How can we get around this? We can remove pointer events from a label once it’s been clicked./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>input:checked + label {\n animation: slideLeft calc(var(--speed) * 1s) forwards;\n pointer-events: none;\n}/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/css-tricks.com/wp-content/uploads/2020/02/bears-02.gif?ssl1 alt classwp-image-303764 data-recalc-dims1/>/figure>\n\n\n\np>Great! Now once we have started, we can’t stop the animation chain from happening./p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_KKwLdXP src//codepen.io/anon/embed/KKwLdXP?height350&theme-id1&slug-hashKKwLdXP&default-tabresult height350 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed KKwLdXP titleCodePen Embed KKwLdXP classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>Next up, we need to crack open the doll to reveal the next one. This is where things get tricky because we are going to need some extra elements, not only to create the effect that the doll is opening up, but also to reveal the next doll inside of it. That\s right: we need to duplicate the inner doll. The trick here is to reveal a fake doll that we swap for the real one once we\ve animated it. This also means delaying the reveal of the next label./p>\n\n\n\np>Now our markup updates labels so that they contains span elements./p>\n\n\n\npre relHTML classwp-block-csstricks-code-block language-markup data-line>code markuptt><label classdoll fordoll--1>\n <span classdoll doll--dummy></span>\n <span classdoll__half doll__half--top>Top</span>\n <span classdoll__half doll__half--bottom>Bottom</span>\n</label>/code>/pre>\n\n\n\np>These will act as the “dummy” doll as well as the lid and base for the current doll./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.doll {\n color: #fff;\n cursor: pointer;\n height: 200px;\n font-size: 2rem;\n position: absolute;\n text-align: center;\n width: 100px;\n}\n\n.doll:nth-of-type(even) {\n --bg: #00f;\n --dummy-bg: #f00;\n}\n\n.doll:nth-of-type(odd) {\n --bg: #f00;\n --dummy-bg: #00f;\n}\n\n.doll__half {\n background: var(--bg);\n position: absolute;\n width: 100%;\n height: 50%;\n left: 0;\n}\n\n.doll__half--top {\n top: 0;\n}\n\n.doll__half--bottom {\n bottom: 0;\n}\n\n.doll__dummy {\n background: var(--dummy-bg);\n height: 100%;\n width: 100%;\n position: absolute;\n top: 0;\n left: 0;\n}/code>/pre>\n\n\n\np>The lid requires three translations to create the opening effect: one to pop it up, one to move it left and then one to pop it down./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582756099//bears-03.png?ssl1 alt classwp-image-303765 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1200/v1582756099//bears-03.png 1200w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582756099//bears-03.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>@keyframes open {\n 0% {\n transform: translate(0, 0);\n }\n 33.333333333333336% {\n transform: translate(0, -100%);\n }\n 66.66666666666667% {\n transform: translate(-100%, -100%);\n }\n 100% {\n transform: translate(-100%, 100%);\n }\n}/code>/pre>\n\n\n\np>Next is where we can use CSS custom properties to handle changing values. Once the doll has slid over to the left, we can open it. But how do we know how long to delay it from opening until that happens? We can use the code>--speed/code> custom property we defined earlier to calculate the correct delay./p>\n\n\n\np>It looks a little quick if we use the code>--speed/code> value as it is, so let’s multiply it by two seconds:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>input:checked + .doll {\n animation: slideLeft calc(var(--speed) * 1s) forwards;\n pointer-events: none;\n}\n\ninput:checked + .doll .doll__half--top {\n animation: open calc(var(--speed) * 2s) calc(var(--speed) * 1s) forwards; // highlight\n}/code>/pre>\n\n\n\np>Much better:/p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_LYEopKm src//codepen.io/anon/embed/LYEopKm?height350&theme-id1&slug-hashLYEopKm&default-tabresult height350 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed LYEopKm titleCodePen Embed LYEopKm classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>Now we need to move the inner “dummy” doll to the new position. This animation is like the open animation in that it consists of three stages. Again, that’s one to move up, one to move right, and one to set down. It\s like the slide animation, too. We are going to use CSS custom properties to determine the distance that the doll moves./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>:root {\n // Introduce a new variable that defines how high the dummy doll should pop out.\n --pop-height: 60;\n}\n\n@keyframes move {\n 0% {\n transform: translate(0, 0) translate(0, 0);\n }\n 33.333333333333336% {\n transform: translate(0, calc(var(--pop-height) * -1%)) translate(0, 0);\n }\n 66.66666666666667% {\n transform: translate(0, calc(var(--pop-height) * -1%)) translate(calc((var(--base-slide) * 1px) + var(--slide-distance) * 1%), 0);\n }\n 100% {\n transform: translate(0, calc(var(--pop-height) * -1%)) translate(calc((var(--base-slide) * 1px) + var(--slide-distance) * 1%), calc(var(--pop-height) * 1%));\n }\n}/code>/pre>\n\n\n\np>Almost there! /p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_wvBbYmP src//codepen.io/anon/embed/wvBbYmP?height350&theme-id1&slug-hashwvBbYmP&default-tabresult height350 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed wvBbYmP titleCodePen Embed wvBbYmP classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>The only thing is that the next doll is available as soon as we click a doll. that means we can spam click our way through the set./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/css-tricks.com/wp-content/uploads/2020/02/bears-04.gif?ssl1 alt classwp-image-303767 data-recalc-dims1/>/figure>\n\n\n\np>Technically, the next doll shouldn’t show until the “fake” one has moved into place. It’s only once the “fake” doll is in place that we can hide it and reveal the real one. That means we going to use zero-second scale animations! That\s right. We can play pretend by delaying two zero-second animations and using code>animation-fill-mode/code>./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>@keyframes appear {\n from {\n transform: scale(0);\n }\n}/code>/pre>\n\n\n\np>We actually only need one set of code>@keyframes/code>. because we can re-use what we have to create the opposite movement with code>animation-direction: reverse/code>. With that in mind, all our animations get applied something like this:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>// The next doll\ninput:checked + .doll + input + .doll,\n// The last doll (doesn\t have an input)\ninput:checked + .doll + .doll {\n animation: appear 0s calc(var(--speed) * 5s) both;\n display: block;\n}\n\n// The current doll\ninput:checked + .doll,\n// The current doll that isn\t the first. Specificity prevails\ninput:checked + .doll + input:checked + .doll {\n animation: slideLeft calc(var(--speed) * 1s) forwards;\n pointer-events: none;\n}\n\ninput:checked + .doll .doll__half--top,\ninput:checked + .doll + input:checked + .doll .doll__half--top {\n animation: open calc(var(--speed) * 2s) calc(var(--speed) * 1s) forwards;\n}\n\ninput:checked + .doll .doll__dummy,\ninput:checked + .doll + input:checked + .doll .doll__dummy {\n animation: move calc(var(--speed) * 2s) calc(var(--speed) * 3s) forwards, appear 0s calc(var(--speed) * 5s) reverse forwards;\n}/code>/pre>\n\n\n\np>Note how important the variables are, especially where we are chaining animations. That gets us almost where we need to be./p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_povmxMG src//codepen.io/anon/embed/povmxMG?height350&theme-id1&slug-hashpovmxMG&default-tabresult height350 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed povmxMG titleCodePen Embed povmxMG classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>I can hear it now: They\re all the same size! Yep. That\s the missing piece. They need to scale down. The trick here is to adjust the markup again and make use of CSS custom properties yet again./p>\n\n\n\npre relHTML classwp-block-csstricks-code-block language-html data-line3,5,6,9>code markuptt><input iddoll--0 typecheckbox/>\n<label classdoll fordoll--0 styledisplay: block; --doll-index: 0;>\n <span classdoll__dummy-container>\n <span classdoll__dummy></span>\n </span> //highlight\n <span classdoll__container>\n <span classdoll__half doll__half--top></span>\n <span classdoll__half doll__half--bottom></span>\n </span>\n</label>/code>/pre>\n\n\n\np>We just introduced a CSS custom property inline that tells us the index of the doll. We can use this to generate a scale of each half as well as the fake inner doll. The halves will have to scale to match the actual doll size, but the fake inner doll scale will need to match that of the next doll. Tricky!/p>\n\n\n\np>We can apply these scales inside the containers so that our animations are not affected./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line15,24>code markuptt>:root {\n --scale-step: 0.05;\n}\n\n.doll__container,\n.doll__dummy-container {\n height: 100%;\n left: 0;\n position: absolute;\n top: 0;\n width: 100%;\n}\n\n.doll__container {\n transform: scale(calc(1 - ((var(--doll-index)) * var(--scale-step))));\n transform-origin: bottom;\n}\n\n.doll__dummy {\n height: 100%;\n left: 0;\n position: absolute;\n top: 0;\n transform: scale(calc(1 - ((var(--doll-index) + 1) * var(--scale-step))));\n transform-origin: bottom center;\n width: 100%;\n}/code>/pre>\n\n\n\np>Note how the code>.doll__dummy/code> class uses code>var(--doll-index) + 1)/code> to calculate the scale so that it matches the next doll. 👍/p>\n\n\n\np>Lastly, we re-assign the animation to the code>.doll__dummy-container/code> class instead of the code>.doll__dummy/code> class./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>input:checked + .doll .doll__dummy-container,\ninput:checked + .doll + input:checked + .doll .doll__dummy-container {\n animation: move calc(var(--speed) * 2s) calc(var(--speed) * 3s) forwards, appear 0s calc(var(--speed) * 5s) reverse forwards;\n}/code>/pre>\n\n\n\np>Here\s a demo where the containers have been given a background color to see what’s happening./p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_yLydOwQ src//codepen.io/anon/embed/yLydOwQ?height350&theme-id1&slug-hashyLydOwQ&default-tabresult height350 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed yLydOwQ titleCodePen Embed yLydOwQ classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>We can see that, although the content size changes, they remain the same size. This makes for consistent animation behavior and makes the code easier to maintain./p>\n\n\n\nh3>Finishing touches/h3>\n\n\n\np>Wow, things are looking pretty slick! All we need are some finishing touches and we are done!/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/css-tricks.com/wp-content/uploads/2020/02/bears-905.gif?ssl1 alt classwp-image-303768 data-recalc-dims1/>/figure>\n\n\n\np>The scene starts to look cluttered because we’re stacking the “old” dolls off to the side when a new one is introduced. So let\s slide a doll out of view when the next one is revealed to clean that mess up./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>@keyframes slideOut {\n from {\n transform: translate(calc((var(--base-slide) * -1px) + var(--slide-distance) * -1%), 0);\n }\n to {\n opacity: 0;\n transform: translate(calc((var(--base-slide) * -1px) + var(--slide-distance) * -2%), 0);\n }\n}\n\ninput:checked + .doll,\ninput:checked + .doll + input:checked + .doll {\n animation: slideLeft calc(var(--speed) * 1s) forwards,\n slideOut calc(var(--speed) * 1s) calc(var(--speed) * 6s) forwards;\n pointer-events: none;\n}/code>/pre>\n\n\n\np>The new code>slideOut/code> animation fades the doll out while it translates to the left. Perfect. 👍/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/css-tricks.com/wp-content/uploads/2020/02/bears-06.gif?ssl1 alt classwp-image-303769 data-recalc-dims1/>/figure>\n\n\n\np>That’s it for the CSS trickery we need to make this effect work. All that’s left style the dolls and the scene./p>\n\n\n\np>We have many options to style the dolls. We could use a background image, CSS illustration, SVG, or what have you. We could even throw together some emoji dolls that use random inline hues!/p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_oNgrBYY src//codepen.io/anon/embed/oNgrBYY?height350&theme-id1&slug-hashoNgrBYY&default-tabresult height350 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed oNgrBYY titleCodePen Embed oNgrBYY classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>Let’s go with inline SVG./p>\n\n\n\np>I’m basically using the same underlying mechanics we’ve already covered. The difference is that I’m also generating inline variables for hue and lightness so the bears sport different shirt colors./p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_jOOYMLm src//codepen.io/anon/embed/jOOYMLm?height500&theme-id1&slug-hashjOOYMLm&default-tabresult height500 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed jOOYMLm titleCodePen Embed jOOYMLm classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\nhr classwp-block-separator/>\n\n\n\np>There we have it! Stacking dolls — err, bears — with nothing but HTML and CSS! All the code for all the steps is available in a hrefhttps://codepen.io/collection/nmqWpx>this CodePen collection/a>. Questions or suggestions? Feel free to reach out to me here in the comments./p>\n,protected:e}},{id:303816,slug:lets-say-you-were-going-to-write-a-blog-post-about-dark-mode,title:{rendered:Let’s Say You Were Going to Write a Blog Post About Dark Mode},excerpt:{rendered:p>This is not that blog post. I’m saying let’s say you were. This is not a knock any other blog posts out there about Dark Mode. There are lots of good ones, and I’m a fan of any information-sharing blog post. This is more of a thought exercise on what I think it would take …/p>\n,protected:e},date:2020-02-26T15:10:32,tags:,content:{rendered:\np>This is em>not/em> that blog post. Im saying em>lets say you were/em>. /p>\n\n\n\np>This is not a knock any other blog posts out there about Dark Mode. There are lots of good ones, and Im a fan of any information-sharing blog post. This is more of a thought exercise on what I think it would take to write a em>really great/em> blog post on this subject./p>\n\n\n\n\x3c!--more--\x3e\n\n\n\nul>li>strong>Youd explain what Dark Mode is./strong> You wouldnt dwell on it though, because chances are are people reading a blog post like this already essentially know what it is. /li>li>strong>Youd definitely have a nice demo./strong> Probably multiple demos. One that is very basic so the most important lines of code can be easily seen. Perhaps something that swaps out code>background-color/code> and code>color/code>. The other demo(s) will deal with more complex and real-world scenarios. What do you do with images and background images? SVG strokes and fills? Buttons? Borders? Shadows? These are rare things that sites have, so anyone looking at designing a Dark Mode UI will come across them./li>li>strong>Youd deal with the fact that Dark Mode is a choice that can happen at the operating system level itself./strong> Fortunately, we can detect that in CSS, so youll have to cover how. /li>li>strong>JavaScript might need to know about the operating system choice as well. /strong>Perhaps because some styling is happening at the JavaScript level, but also because of this next thing./li>li>strong>Dark Mode could (should?) be a choice on the website as well./strong> That serves cases where, on this particular site, a user prefers a choice opposite of what their operating system preference is. /li>li>strong>Building a theme toggle isnt a small job./strong> If your site has authentication, that choice should probably be remembered at the account level. If it doesnt, the choice should be remembered in some other way. One possibility is code>localStorage/code>, but that can have problems, like the fact that CSS is generally applied to a page before JavaScript executes, meaning youre facing a \flash of incorrect theme\ situation. You might be needing to deal with cookies so that you can send theme-specific CSS on each page load./li>li>strong>Your blog post would include real-world examples of people already doing this./strong> That way, you can investigate how theyve done it and evaluate how successful they were. Perhaps you can reach out to them for comment as well. If there are some em>bad/em> examples out there, you should cover those too, sometimes learning is best done by learning what to avoid./li>li>strong>Youll be aware of other writing on this subject. /strong>That should not dissuade you from writing about the subject yourself, but a blog post that sounds like youre the first and only person writing about a subject when you clearly arent has an awkward tone to it that doesnt come across well. Not only can you learn from others writing, but you can also pull from it and potentially take it further./li>li>strong>Since youll be covering browser technology, youll be covering the support of that technology across the browser landscape/strong>. Are there notable exceptions in support? Is that support coming? Have you researched what browsers themselves are saying about the technology? /li>li>strong>There are accessibility implications abound./strong> Dark Mode itself can be considered an accessibility feature, and there are tangential accessibility issues here too, like how the toggle works, how mode changes are announced, and a whole new set of a href\https://css-tricks.com/understanding-web-accessibility-color-contrast-guidelines-and-ratios/\>color contrasts to calculate/a> and get right. A blog post is a great opportunity to talk about all that. Have you researched it? Have you talked to any people who have special needs around these features? Any experts? Have you read what accessibility people are saying about Dark Mode?/li>/ul>\n\n\n\np>That was all about Dark Mode, but I bet you could imagine how considering all these points could benefit any blog post covering a technical concept. /p>\n,protected:e}},{id:304090,slug:chameleonic-header,title:{rendered:Chameleonic Header},excerpt:{rendered:p>Nice demo from Sebastiano Guerriero. When a fixed-position header moves from overlapping differently-colored backgrounds, the colors flop out to be appropriate for that background. Sebastiano’s technique is very clever, involving multiple copies of the header within each section (where the copies are hidden from screenreaders) which are all positioned on top of each other and …/p>\n,protected:e},date:2020-02-26T15:10:25,tags:,content:{rendered:\np>Nice a hrefhttps://codyhouse.co/demo-tutorials/chameleonic-header/index.html>demo/a> from Sebastiano Guerriero. When a fixed-position header moves from overlapping differently-colored backgrounds, the colors flop out to be appropriate for that background. Sebastiano\s technique is very clever, involving multiple copies of the header within each section (where the copies are hidden from screenreaders) which are all positioned on top of each other and then revealed as the new section comes, thanks to each section having a code>clip-path/code> around it. /p>\n\n\n\np>A bonafide CSS trick if I\ve ever seen one./p>\n\n\n\np>It makes me wish there was an easier way of doing it. Like, what if there was some magical value of code>a hrefhttps://css-tricks.com/almanac/properties/m/mix-blend-mode/>mix-blend-mode/a>/code> that would handle it? a hrefhttps://codepen.io/chriscoyier/pen/poJEmmL>I got close enough/a> that it gives me hope. /p>\n,protected:e}},{id:303448,slug:weaving-a-line-through-text-in-css,title:{rendered:Weaving a Line Through Text in CSS},excerpt:{rendered:p>Earlier this year, I came across this demo by Florin Pop, which makes a line go either over or under the letters of a single line heading. I thought this was a cool idea, but there were a few little things about the implementation I felt I could simplify and improve at the same time./p>\n,protected:e},date:2020-02-26T08:04:24,tags:478,708,1147,content:{rendered:\np>Earlier this year, I came across a hrefhttps://codepen.io/FlorinPop17/pen/LYYGMOV>this demo/a> by Florin Pop, which makes a line go either over or under the letters of a single line heading. I thought this was a cool idea, but there were a few little things about the implementation I felt I could simplify and improve at the same time./p>\n\n\n\n\x3c!--more--\x3e\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755245//interweaving-headline.png?ssl1 alt classwp-image-303821 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1544/v1582755245//interweaving-headline.png 1544w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755245//interweaving-headline.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>First off, the original demo duplicates the headline text, which I knew could be easily avoided. Then there\s the fact that the length of the line going through the text is a magic number, which is not a very flexible approach. And finally, can\t we get rid of the JavaScript?/p>\n\n\n\np>So let\s take a look into where I ended up taking this./p>\n\n\n\nh3 idstructure>HTML structure/h3>\n\n\n\np>Florin puts the text into a heading element and then duplicates this heading, using a hrefhttps://splitting.js.org/>Splitting.js/a> to replace the text content of the duplicated heading with spans, each containing one letter of the original text./p>\n\n\n\np>Already having decided to do this without text duplication, using a library to split the text into characters and then put each into a code>span/code> feels a bit like overkill, so we\re doing it all with an HTML preprocessor./p>\n\n\n\npre relPug classwp-block-csstricks-code-block language-none data-line>code markuptt>- let text \We Love to Play\;\n- let arr text.split(\\);\n\nh1(role\image\ aria-labeltext)\n - arr.forEach(letter > {\n span.letter #{letter}\n - });/code>/pre>\n\n\n\np>Since splitting text into multiple elements may not work nicely with screen readers, we\ve given the whole thing a code>role/code> of code>image/code> and an code>aria-label/code>./p>\n\n\n\np>This generates the following HTML:/p>\n\n\n\npre relHTML classwp-block-csstricks-code-block language-markup data-line>code markuptt><h1 roleimage aria-labelWe Love to Play>\n <span classletter>W</span>\n <span classletter>e</span>\n <span classletter> </span>\n <span classletter>L</span>\n <span classletter>o</span>\n <span classletter>v</span>\n <span classletter>e</span>\n <span classletter> </span>\n <span classletter>t</span>\n <span classletter>o</span>\n <span classletter> </span>\n <span classletter>P</span>\n <span classletter>l</span>\n <span classletter>a</span>\n <span classletter>y</span>\n</h1>/code>/pre>\n\n\n\nh3 idbasic-styles>Basic styles/h3>\n\n\n\np>We place the heading in the middle of its parent (the code>body/code> in this case) by using a code>grid/code> layout:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>body {\n display: grid;\n place-content: center;\n}/code>/pre>\n\n\n\nfigure classwp-block-image>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755247//grid_item.png?ssl1 altScreenshot of grid layout lines around the centrally placed heading when inspecting it with Firefox DevTools. classwp-image-303467 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1000/v1582755247//grid_item.png 1000w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_856/v1582755247//grid_item.png 856w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_696/v1582755247//grid_item.png 696w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_457/v1582755247//grid_item.png 457w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755247//grid_item.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>The heading doesn\t stretch across its parent to cover its entire code>width/code>, but is instead placed in the middle./figcaption>/figure>\n\n\n\np>We may also add some prettifying touches, like a nice code>font/code> or a code>background/code> on the container./p>\n\n\n\np>Next, we create the line with an absolutely positioned code>::after/code> pseudo-element of thickness (code>height/code>) code>$h/code>:/p>\n\n\n\npre relSCSS classwp-block-csstricks-code-block language-scss data-line>code markuptt>$h: .125em;\n$r: .5*$h;\n\nh1 {\n position: relative;\n \n &::after {\n position: absolute;\n top: calc(50% - #{$r}); right: 0;\n height: $h;\n border-radius: 0 $r $r 0;\n background: crimson;\n }\n}/code>/pre>\n\n\n\np>The above code takes care of the positioning and code>height/code> of the pseudo-element, but what about the code>width/code>? How do we make it stretch from the left edge of the viewport to the right edge of the heading text?/p>\n\n\n\nh3 idline-length>Line length/h3>\n\n\n\np>Well, since we have a code>grid/code> layout where the heading is middle-aligned horizontally, this means that the vertical midline of the viewport coincides with that of the heading, splitting both into two equal-width halves:/p>\n\n\n\nfigure classwp-block-image>img srchttps://css-tricks.com/wp-content/uploads/2020/02/heading_viewport_split.svg altSVG illustration. Shows how the vertical midline of the viewport coincides with that of the heading and splits both into equal width halves./>figcaption>The middle-aligned heading./figcaption>/figure>\n\n\n\np>Consequently, the distance between the left edge of the viewport and the right edge of the heading is half the viewport width (code>50vw/code>) plus half the heading width, which can be expressed as a code>%/code> value when used in the computation of its pseudo-element\s code>width/code>./p>\n\n\n\np>So the code>width/code> of our code>::after/code> pseudo-element is:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>width: calc(50vw + 50%);/code>/pre>\n\n\n\nh3 idover-and-under>Making the line go over and under/h3>\n\n\n\np>So far, the result is just a crimson line crossing some black text:/p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_RwPNxNG src//codepen.io/anon/embed/RwPNxNG?height250&theme-id1&slug-hashRwPNxNG&default-tabresult height250 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed RwPNxNG titleCodePen Embed RwPNxNG classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>What we want is for some of the letters to show up on top of the line. In order to get this effect, we give them (or we don\t give them) a class of code>.over/code> at random. This means slightly altering the Pug code:/p>\n\n\n\npre relPug classwp-block-csstricks-code-block language-none data-line>code markuptt>- let text \We Love to Play\;\n- let arr text.split(\\);\n\nh1(role\image\ aria-labeltext)\n - arr.forEach(letter > {\n span.letter(classMath.random() > .5 ? \over\ : null) #{letter}\n - });/code>/pre>\n\n\n\np>We then relatively position the letters with a class of code>.over/code> and give them a positive code>z-index/code>./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.over {\n position: relative;\n z-index: 1;\n}/code>/pre>\n\n\n\np classexplanation>My initial idea involved using code>translatez(1px)/code> instead of code>z-index: 1/code>, but then it hit me that using code>z-index/code> has both better browser support and involves less effort./p>\n\n\n\np>The line passes over some letters, but underneath others:/p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_oNXgpxj src//codepen.io/anon/embed/oNXgpxj?height250&theme-id1&slug-hashoNXgpxj&default-tabresult height250 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed oNXgpxj titleCodePen Embed oNXgpxj classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\nh3 idanimation>Animate it!/h3>\n\n\n\np>Now that we got over the tricky part, we can also add in an code>animation/code> to make the line enter in. This means having the crimson line shift to the left (in the negative direction of the x-axis, so the sign will be minus) by its full code>width/code> (code>100%/code>) at the beginning, only to then allow it to go back to its normal position./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>@keyframes slide { 0% { transform: translate(-100%); } }/code>/pre>\n\n\n\np>I opted to have a bit of time to breathe before the start of the code>animation/code>. This meant adding in the code>1s/code> delay which, in turn, meant adding the code>backwards/code> keyword for the code>animation-fill-mode/code>, so that the line would stay in the state specified by the code>0%/code> keyframe before the start of the code>animation/code>:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>animation: slide 2s ease-out 1s backwards;/code>/pre>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_vYErMKQ src//codepen.io/anon/embed/vYErMKQ?height250&theme-id1&slug-hashvYErMKQ&default-tabresult height250 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed vYErMKQ titleCodePen Embed vYErMKQ classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\nh3 id3d-touch>A 3D touch/h3>\n\n\n\np>Doing this gave me another idea, which was to make the line go through every single letter, that is, start above the letter, go through it and finish underneath (or the other way around)./p>\n\n\n\np>This requires real 3D and a few small tweaks./p>\n\n\n\np>First off, we set code>transform-style/code> to code>preserve-3d/code> on the heading since we want all its children (and pseudo-elements) to a be part of the same 3D assembly, which will make them be ordered and intersect according to how they\re positioned in 3D./p>\n\n\n\np>Next, we want to rotate each letter around its y-axis, with the direction of rotation depending on the presence of the randomly assigned class (whose name we change to code>.rev/code> from reverse as over isn\t really suggestive of what we\re doing here anymore)./p>\n\n\n\np>However, before we do this, we need to remember our span elements are still inline ones at this point and setting a code>transform/code> on an inline element has absolutely no effect./p>\n\n\n\np>To get around this issue, we set code>display: flex/code> on the heading. However, this creates a new issue and that\s the fact that span elements that contain only a space (code> /code>) get squished to zero code>width/code>./p>\n\n\n\nfigure classwp-block-image>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755256//space_flex_item.png?ssl1 altScreenshot showing how the span containing only a space gets squished to zero width when setting `display: flex` on its parent. classwp-image-303473 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1000/v1582755256//space_flex_item.png 1000w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_843/v1582755256//space_flex_item.png 843w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_654/v1582755256//space_flex_item.png 654w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_432/v1582755256//space_flex_item.png 432w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755256//space_flex_item.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Inspecting a space only code><span>/code> in Firefox DevTools./figcaption>/figure>\n\n\n\np>A simple fix for this is to set code>white-space: pre/code> on our code>.letter/code> spans./p>\n\n\n\np>Once we\ve done this, we can rotate our spans by an angle code>$a/code>... in one direction or the other!/p>\n\n\n\npre relSCSS classwp-block-csstricks-code-block language-scss data-line>code markuptt>$a: 2deg;\n\n.letter {\n white-space: pre;\n transform: rotatey($a);\n}\n\n.rev { transform: rotatey(-$a); }/code>/pre>\n\n\n\np>Since rotation around the y-axis squishes our letters horizontally, we can scale them along the x-axis by a factor (code>$f/code>) that\s the inverse of the cosine of code>$a/code>./p>\n\n\n\npre relSCSS classwp-block-csstricks-code-block language-scss data-line>code markuptt>$a: 2deg;\n$f: 1/cos($a)\n\n.letter {\n white-space: pre;\n transform: rotatey($a) scalex($f)\n}\n\n.rev { transform: rotatey(-$a) scalex($f) }/code>/pre>\n\n\n\np classexplanation>If you wish to understand the why behind using this particular scaling factor, you can check out this older a hrefhttps://css-tricks.com/solving-last-item-problem-circular-distribution-partially-overlapping-items/>article/a> where I explain it all in detail./p>\n\n\n\np>And that\s it! We now have the 3D result we\ve been after! Do note however that the font used here was chosen so that our result looks good and another font may not work as well./p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_KKpwmEg src//codepen.io/anon/embed/KKpwmEg?height350&theme-id1&slug-hashKKpwmEg&default-tabresult height350 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed KKpwmEg titleCodePen Embed KKpwmEg classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n,protected:e}},{id:304054,slug:in-browser-performance-linting-with-feature-policies,title:{rendered:In-Browser Performance Linting With Feature Policies},excerpt:{rendered:p>Here’s a neat idea from Tim Kadlec. He uses the Modheader extension to toggle custom headers in his browser. It also lets him see when images are too big and need to be optimized in some way. This is a great way to catch issues like this in a local environment because browsers will throw …/p>\n,protected:e},date:2020-02-26T08:04:05,tags:1663,1006,694,592,content:{rendered:\np>Here’s a neat idea from Tim Kadlec. He uses the a hrefhttps://chrome.google.com/webstore/detail/modheader/idgpnmonknjnojddfkpgkljpfnnfcklj>Modheader/a> extension to toggle custom headers in his browser. It also lets him see when images are too big and need to be optimized in some way. This is a great way to catch issues like this in a local environment because browsers will throw an error and won’t display them at all!/p>\n\n\n\n\x3c!--more--\x3e\n\n\n\np>As Tim mentions, the trick is with the code>Feature Policy/code> header with the code>oversized-images/code> policy, and he toggles it on like this:/p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>Feature-Policy: oversized-images ‘none’;/code>/pre>\n\n\n\np>Tim writes:/p>\n\n\n\nblockquote classwp-block-quote>p>By default, if you provide the browser an image in a format it supports, it will display it. It even helpful scales those images so they look great, even if you’ve provided a massive file. Because of this, it’s not immediately obvious when you’ve provided an image that is larger than the site needs./p>p>The a hrefhttps://github.com/w3c/webappsec-feature-policy/blob/master/policies/optimized-images.md#oversized-images>code>oversized-images/code> policy/a> tells the browser not to allow any images that are more than some predefined factor of their container size. The recommended default threshold is 2x, but you are able to override that if you would like./p>/blockquote>\n\n\n\np>I love this idea of using the browser to do linting work for us! I wonder what other ways we could use the browser to place guard rails around our work to prevent future mistakes.../p>\n,protected:e}},{id:304202,slug:instant-graphql-backend-using-faunadb,title:{rendered:Instant GraphQL Backend with Fine-grained Security Using FaunaDB},excerpt:{rendered:p>GraphQL is becoming popular and developers are constantly looking for frameworks that make it easy to set up a fast, secure and scalable GraphQL API. In this article, we will learn how to create a scalable and fast GraphQL API with authentication and fine-grained data-access control (authorization). As an example, we’ll build an API with …/p>\n,protected:e},date:2020-02-25T10:31:34,tags:,content:{rendered:\np>GraphQL is becoming popular and developers are constantly looking for frameworks that make it easy to set up a fast, secure and scalable GraphQL API. In this article, we will learn how to create a scalable and fast GraphQL API with authentication and fine-grained data-access control (authorization). As an example, we’ll build an API with register and login functionality. The API will be about users and confidential files so we’ll define advanced authorization rules that specify whether a logged-in user can access certain files. /p>\n\n\n\np>By using FaunaDB’s native GraphQL and security layer, we receive all the necessary tools to set up such an API in minutes. a hrefhttps://synd.co/2SVX2zq>FaunaDB has a free tier/a> so you can easily follow along by creating an account at a hrefhttps://synd.co/2SVX2zq>https://dashboard.fauna.com/a>a hrefhttps://dashboard.fauna.com/>//a>. Since FaunaDB automatically provides the necessary indexes and translates each GraphQL query to one FaunaDB query, your API is also as fast as it can be (a hrefhttps://jaxenter.com/faunadbs-graphql-api-165568.html>no n+1 problems!/a>)./p>\n\n\n\np>Setting up the API is simple: drop in a schema and we are ready to start. So let’s get started! /p>\n\n\n\n\x3c!--more--\x3e\n\n\n\nh1>The use-case: users and confidential files/h1>\n\n\n\np>We need an example use-case that demonstrates how security and GraphQL API features can work together. In this example, there are strong>users/strong> and strong>files./strong> Some files can be accessed by all users, and some are only meant to be accessed by managers. The following GraphQL schema will define our model:/p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>type User {\n username: String! @unique\n role: UserRole!\n}\n\nenum UserRole {\n MANAGER\n EMPLOYEE\n}\n\ntype File {\n content: String!\n confidential: Boolean!\n}\n\ninput CreateUserInput {\n username: String!\n password: String!\n role: UserRole!\n}\n\ninput LoginUserInput {\n username: String!\n password: String!\n}\n\ntype Query {\n allFiles: File!!\n}\n\ntype Mutation {\n createUser(input: CreateUserInput): User! @resolver(name: create_user)\n loginUser(input: LoginUserInput): String! @resolver(name: login_user)\n}/code>/pre>\n\n\n\np>When looking at the schema, you might notice that the code>createUser/code> and code>loginUser/code> Mutation fields have been annotated with a special directive named a hrefhttps://docs.fauna.com/fauna/current/api/graphql/directives/d_resolver>code>@resolver/code>/a>. This is a directive provided by the a hrefhttps://synd.co/2SVX2zq>FaunaDB/a> GraphQL API, which allows us to define a custom behavior for a given Query or Mutation field. Since we’ll be using FaunaDB’s built-in authentication mechanisms, we will need to define this logic in a hrefhttps://synd.co/2SVX2zq>FaunaDB/a> after we import the schema. /p>\n\n\n\nh3>Importing the schema/h3>\n\n\n\np>First, let’s import the example schema into a new database. Log into the FaunaDB a hrefhttps://dashboard.fauna.com/>Cloud Console/a> with your credentials. If you don’t have an account yet, you can sign up for free in a few seconds./p>\n\n\n\np>Once logged in, click the New Database button from the home page:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754670//01-new-database-2-1.png?ssl1 alt classwp-image-304206 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754670//01-new-database-2-1.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1349/v1582754670//01-new-database-2-1.png 1349w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1087/v1582754670//01-new-database-2-1.png 1087w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_657/v1582754670//01-new-database-2-1.png 657w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754670//01-new-database-2-1.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Choose a name for the new database, and click the Save button: /p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754712//02-new-database-2.png?ssl1 alt classwp-image-304207 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754712//02-new-database-2.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1032/v1582754712//02-new-database-2.png 1032w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754712//02-new-database-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Next, we will import the GraphQL schema listed above into the database we just created. To do so, create a file named code>schema.gql/code> containing the schema definition. Then, select the GRAPHQL tab from the left sidebar, click the Import Schema button, and select the newly-created file: /p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754711//04-import-schema-2.png?ssl1 alt classwp-image-304208 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754711//04-import-schema-2.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1311/v1582754711//04-import-schema-2.png 1311w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_814/v1582754711//04-import-schema-2.png 814w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754711//04-import-schema-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>The import process creates all of the necessary database elements, including collections and indexes, for backing up all of the types defined in the schema. It automatically creates everything your GraphQL API needs to run efficiently. /p>\n\n\n\np>You now have a fully functional GraphQL API which you can start testing out in the GraphQL playground. But we do not have data yet. More specifically, we would like to create some users to start testing our GraphQL API. However, since users will be part of our authentication, they are special: they have credentials and can be impersonated. Let’s see how we can create some users with secure credentials!/p>\n\n\n\nh3>Custom resolvers for authentication/h3>\n\n\n\np>Remember the code>createUser/code> and code>loginUser/code> mutation fields that have been annotated with a special directive named code>@resolver/code>. code>createUser/code> is exactly what we need to start creating users, however the schema did not really define how a user needs to created; instead, it was tagged with a code>@resolver/code> tag./p>\n\n\n\np>By tagging a specific mutation with a custom resolver such as code>@resolver(name: create_user)/code> we are informing FaunaDB that this mutation is not implemented yet but will be implemented by a a hrefhttps://docs.fauna.com/fauna/current/api/graphql/functions>User-defined function/a> (UDF). Since our GraphQL schema does not know how to express this, the import process will only create a function template which we still have to fill in./p>\n\n\n\np>A UDF is a custom FaunaDB function, similar to a em>stored procedure/em>, that enables users to define a tailor-made operation in Fauna’s Query Language (a hrefhttps://docs.fauna.com/fauna/current/api/fql/>FQL/a>). This function is then used as the resolver of the annotated field. /p>\n\n\n\np>We will need a custom resolver since we will take advantage of the built-in authentication capabilities which can not be expressed in standard GraphQL. FaunaDB allows you to set a password on any database entity. This password can then be used to impersonate this database entity with the code>Login/code> function which returns a token with certain permissions. The permissions that this token holds depend on the access rules that we will write./p>\n\n\n\np>Let’s continue to implement the UDF for the code>createUser/code> field resolver so that we can create some test users. First, select the Shell tab from the left sidebar:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754710//05-shell-2.png?ssl1 alt classwp-image-304209 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754710//05-shell-2.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1448/v1582754710//05-shell-2.png 1448w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_904/v1582754710//05-shell-2.png 904w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754710//05-shell-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>As explained before, a template UDF has already been created during the import process. When called, this template UDF prints an error message stating that it needs to be updated with a proper implementation. In order to update it with the intended behavior, we are going to use FQL\s a hrefhttps://docs.fauna.com/fauna/current/api/fql/functions/update>Update/a> function./p>\n\n\n\np>So, let’s copy the following FQL query into the web-based shell, and click the Run Query button:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>Update(Function(create_user), {\n body: Query(\n Lambda(input,\n Create(Collection(User), {\n data: {\n username: Select(username, Var(input)),\n role: Select(role, Var(input)),\n },\n credentials: {\n password: Select(password, Var(input))\n }\n }) \n )\n )\n});/code>/pre>\n\n\n\np>Your screen should look similar to:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754710//06-create-user-udf-2.png?ssl1 alt classwp-image-304210 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754710//06-create-user-udf-2.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1260/v1582754710//06-create-user-udf-2.png 1260w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_775/v1582754710//06-create-user-udf-2.png 775w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754710//06-create-user-udf-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>The code>create_user/code> UDF will be in charge of properly creating a User document along with a password value. The password is stored in the document within a special object named em>credentials/em> that is encrypted and cannot be retrieved back by any FQL function. As a result, the password is securely saved in the database making it impossible to read from either the FQL or the GraphQL APIs. The password will be used later for authenticating a User through a dedicated FQL function named a hrefhttps://docs.fauna.com/fauna/current/api/fql/functions/login>code>Login/code>/a>, as explained next./p>\n\n\n\np>Now, let’s add the proper implementation for the UDF backing up the code>loginUser/code> field resolver through the following FQL query:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>Update(Function(login_user), {\n body: Query(\n Lambda(input,\n Select(\n secret,\n Login(\n Match(Index(unique_User_username), Select(username, Var(input))), \n { password: Select(password, Var(input)) }\n )\n )\n )\n )\n});/code>/pre>\n\n\n\np>Copy the query listed above and paste it into the shell’s command panel, and click the Run Query button:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754709//07-login-user-2.png?ssl1 alt classwp-image-304211 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754709//07-login-user-2.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1221/v1582754709//07-login-user-2.png 1221w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_740/v1582754709//07-login-user-2.png 740w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754709//07-login-user-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>The code>login_user/code> UDF will attempt to authenticate a User with the given username and password credentials. As mentioned before, it does so via the a hrefhttps://docs.fauna.com/fauna/current/api/fql/functions/login>code>Login/code>/a> function. The code>Login/code> function verifies that the given password matches the one stored along with the User document being authenticated. Note that the password stored in the database is not output at any point during the login process. Finally, in case the credentials are valid, the code>login_user/code> UDF returns an authorization token called a em>secret/em> which can be used in subsequent requests for validating the User’s identity./p>\n\n\n\np>With the resolvers in place, we will continue with creating some sample data. This will let us try out our use case and help us better understand how the access rules are defined later on./p>\n\n\n\nh3>Creating sample data/h3>\n\n\n\np>First, we are going to create a em>manager/em> user. Select the GraphQL tab from the left sidebar, copy the following mutation into the GraphQL Playground, and click the Play button:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>mutation CreateManagerUser {\n createUser(input: {\n username: bill.lumbergh\n password: 123456\n role: MANAGER\n }) {\n username\n role\n }\n}/code>/pre>\n\n\n\np>Your screen should look like this:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754708//09-create-manager.png?ssl1 alt classwp-image-304212 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754708//09-create-manager.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1361/v1582754708//09-create-manager.png 1361w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1046/v1582754708//09-create-manager.png 1046w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_632/v1582754708//09-create-manager.png 632w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754708//09-create-manager.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Next, let’s create an em>employee/em> user by running the following mutation through the GraphQL Playground editor:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>mutation CreateEmployeeUser {\n createUser(input: {\n username: peter.gibbons\n password: abcdef\n role: EMPLOYEE\n }) {\n username\n role\n }\n}/code>/pre>\n\n\n\np>You should see the following response:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754704//10-create-employee-2-2.png?ssl1 alt classwp-image-304218 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754704//10-create-employee-2-2.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1366/v1582754704//10-create-employee-2-2.png 1366w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1046/v1582754704//10-create-employee-2-2.png 1046w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_630/v1582754704//10-create-employee-2-2.png 630w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754704//10-create-employee-2-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Now, let’s create a em>confidential/em> file by running the following mutation:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>mutation CreateConfidentialFile {\n createFile(data: {\n content: This is a confidential file!\n confidential: true\n }) {\n content\n confidential\n }\n}/code>/pre>\n\n\n\np>As a response, you should get the following:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754703//Screen-Shot-2019-11-12-at-15.36.40-3.png?ssl1 alt classwp-image-304219 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754703//Screen-Shot-2019-11-12-at-15.36.40-3.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1346/v1582754703//Screen-Shot-2019-11-12-at-15.36.40-3.png 1346w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1045/v1582754703//Screen-Shot-2019-11-12-at-15.36.40-3.png 1045w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_630/v1582754703//Screen-Shot-2019-11-12-at-15.36.40-3.png 630w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754703//Screen-Shot-2019-11-12-at-15.36.40-3.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>And lastly, create a em>public/em> file with the following mutation:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>mutation CreatePublicFile {\n createFile(data: {\n content: This is a public file!\n confidential: false\n }) {\n content\n confidential\n }\n}/code>/pre>\n\n\n\np>If successful, it should prompt the following response:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754702//12-create-public-file.png?ssl1 alt classwp-image-304220 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754702//12-create-public-file.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1319/v1582754702//12-create-public-file.png 1319w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1057/v1582754702//12-create-public-file.png 1057w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_639/v1582754702//12-create-public-file.png 639w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754702//12-create-public-file.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Now that all the sample data is in place, we need access rules since this article is about securing a GraphQL API. The access rules determine how the sample data we just created can be accessed, since by default a user can only access his own user entity. In this case, we are going to implement the following access rules: /p>\n\n\n\nol>li>Allow employee users to read public files only./li>li>Allow manager users to read both public files and, only during weekdays, confidential files./li>/ol>\n\n\n\np>As you might have already noticed, these access rules are highly specific. We will see however that the ABAC system is powerful enough to express very complex rules without getting in the way of the design of your GraphQL API./p>\n\n\n\np>Such access rules are not part of the GraphQL specification so we will define the access rules in the Fauna Query Language (FQL), and then verify that they are working as expected by executing some queries from the GraphQL API. /p>\n\n\n\np>But what is this ABAC system that we just mentioned? What does it stand for, and what can it do?/p>\n\n\n\nh3>What is ABAC?/h3>\n\n\n\np>ABAC stands for em>Attribute-Based Access Control/em>. As its name indicates, it’s an authorization model that establishes access policies based on em>attributes/em>. In simple words, it means that you can write security rules that involve any of the attributes of your data. If our data contains users we could use the role, department, and clearance level to grant or refuse access to specific data. Or we could use the current time, day of the week, or location of the user to decide whether he can access a specific resource. /p>\n\n\n\np>In essence, ABAC allows the definition of em>fine-grained/em> access control policies based on environmental properties and your data. Now that we know what it can do, let’s define some access rules to give you concrete examples./p>\n\n\n\nh3>Defining the access rules/h3>\n\n\n\np>In FaunaDB, access rules are defined in the form of roles. A role consists of the following data:/p>\n\n\n\nul>li>name — the name that identifies the role/li>li>a hrefhttps://docs.fauna.com/fauna/current/security/abac#privileges>privileges/a> — specific actions that can be executed on specific resources /li>li>a hrefhttps://docs.fauna.com/fauna/current/security/abac#membership>membership/a> — specific identities that should have the specified privileges/li>/ul>\n\n\n\np>Roles are created through the a hrefhttps://docs.fauna.com/fauna/current/api/fql/functions/createrole>code>CreateRole/code>/a> FQL function, as shown in the following example snippet:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>CreateRole({\n name: role_name,\n membership: // ... ,\n privileges: // ... \n})/code>/pre>\n\n\n\np>You can see two important concepts in this role; strong>membership /strong>and strong>privileges. /strong>Membership defines who receives the privileges of the role and privileges defines what these permissions are. Let’s write a simple example rule to start with: em>“Any user can read all files.”/em>/p>\n\n\n\np>Since the rule applies on all users, we would define the membership like this: /p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>membership: {\n resource: Collection(User)\n}/code>/pre>\n\n\n\np>Simple right? We then continue to define the Can read all files privilege for all of these users./p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>privileges: \n {\n resource: Collection(File),\n actions: { read: true }\n }\n/code>/pre>\n\n\n\np>The direct effect of this is that any token that you receive by logging in with a user via our code>loginUser/code> GraphQL mutation can now access all files. /p>\n\n\n\np>This is the simplest rule that we can write, but in our example we want to limit access to some confidential files. To do that, we can replace the code>{read: true}/code> syntax with a function. Since we have defined that the resource of the privilege is the File collection, this function will take each file that would be accessed by a query as the first parameter. You can then write rules such as: “A user can only access a file if it is not confidential”. In FaunaDB’s FQL, such a function is written by using code>Query(Lambda(‘x’, … <logic that users Var(‘x’)>))/code>.br>/p>\n\n\n\np>Below is the privilege that would only provide read access to non-confidential files: /p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line9>code markuptt>privileges: \n {\n resource: Collection(File),\n actions: {\n // Read and establish rule based on action attribute\n read: Query(\n // Read and establish rule based on resource attribute\n Lambda(fileRef,\n Not(Select(data, confidential, Get(Var(fileRef))))\n )\n )\n }\n }\n/code>/pre>\n\n\n\np>This directly uses properties of the File resource we are trying to access. Since it’s just a function, we could also take into account environmental properties like the current time. For example, let’s write a rule that only allows access on weekdays. /p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line7-12>code markuptt>privileges: \n {\n resource: Collection(File),\n actions: {\n read: Query(\n Lambda(fileRef,\n Let(\n {\n dayOfWeek: DayOfWeek(Now())\n },\n And(GTE(Var(dayOfWeek), 1), LTE(Var(dayOfWeek), 5)) \n )\n )\n )\n }\n }\n/code>/pre>\n\n\n\np>As mentioned in our rules, confidential files should only be accessible by managers. Managers are also users, so we need a rule that applies to a specific segment of our collection of users. Luckily, we can also define the membership as a function; for example, the following Lambda only considers users who have the code>MANAGER/code> role to be part of the role membership. /p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line5>code markuptt>membership: {\n resource: Collection(User),\n predicate: Query( // Read and establish rule based on user attribute\n Lambda(userRef, \n Equals(Select(data, role, Get(Var(userRef))), MANAGER)\n )\n )\n}/code>/pre>\n\n\n\np>In sum, FaunaDB roles are very flexible entities that allow defining access rules based on all of the system elements\ attributes, with different levels of granularity. The place where the rules are defined — privileges or membership — determines their granularity and the attributes that are available, and will differ with each particular use case./p>\n\n\n\np>Now that we have covered the basics of how roles work, let’s continue by creating the access rules for our example use case!/p>\n\n\n\np>In order to keep things neat and tidy, we’re going to create two roles: one for each of the access rules. This will allow us to extend the roles with further rules in an organized way if required later. Nonetheless, be aware that all of the rules could also have been defined together within just one role if needed./p>\n\n\n\np>Let’s implement the first rule: /p>\n\n\n\np>em>“Allow employee users to read public files only.”/em>/p>\n\n\n\np>In order to create a role meeting these conditions, we are going to use the following query:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>CreateRole({\n name: employee_role,\n membership: {\n resource: Collection(User),\n predicate: Query( \n Lambda(userRef,\n // User attribute based rule:\n // It grants access only if the User has EMPLOYEE role.\n // If so, further rules specified in the privileges\n // section are applied next. \n Equals(Select(data, role, Get(Var(userRef))), EMPLOYEE)\n )\n )\n },\n privileges: \n {\n // Note: \allFiles\ Index is used to retrieve the \n // documents from the File collection. Therefore, \n // read access to the Index is required here as well.\n resource: Index(allFiles),\n actions: { read: true } \n },\n {\n resource: Collection(File),\n actions: {\n // Action attribute based rule:\n // It grants read access to the File collection.\n read: Query(\n Lambda(fileRef,\n Let(\n {\n file: Get(Var(fileRef)),\n },\n // Resource attribute based rule:\n // It grants access to public files only.\n Not(Select(data, confidential, Var(file)))\n )\n )\n )\n }\n }\n \n})/code>/pre>\n\n\n\np>Select the Shell tab from the left sidebar, copy the above query into the command panel, and click the Run Query button:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754702//08.01-create-employee-role-2.png?ssl1 alt classwp-image-304221 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754702//08.01-create-employee-role-2.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1287/v1582754702//08.01-create-employee-role-2.png 1287w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_782/v1582754702//08.01-create-employee-role-2.png 782w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754702//08.01-create-employee-role-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Next, let’s implement the second access rule:/p>\n\n\n\np>em>“Allow manager users to read both public files and, only during weekdays, confidential files.”/em>/p>\n\n\n\np>In this case, we are going to use the following query:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>CreateRole({\n name: manager_role,\n membership: {\n resource: Collection(User),\n predicate: Query(\n Lambda(userRef, \n // User attribute based rule:\n // It grants access only if the User has MANAGER role.\n // If so, further rules specified in the privileges\n // section are applied next.\n Equals(Select(data, role, Get(Var(userRef))), MANAGER)\n )\n )\n },\n privileges: \n {\n // Note: \allFiles\ Index is used to retrieve\n // documents from the File collection. Therefore, \n // read access to the Index is required here as well.\n resource: Index(allFiles),\n actions: { read: true } \n },\n {\n resource: Collection(File),\n actions: {\n // Action attribute based rule:\n // It grants read access to the File collection.\n read: Query(\n Lambda(fileRef,\n Let(\n {\n file: Get(Var(fileRef)),\n dayOfWeek: DayOfWeek(Now())\n },\n Or(\n // Resource attribute based rule:\n // It grants access to public files.\n Not(Select(data, confidential, Var(file))),\n // Resource and environmental attribute based rule:\n // It grants access to confidential files only on weekdays.\n And(\n Select(data, confidential, Var(file)),\n And(GTE(Var(dayOfWeek), 1), LTE(Var(dayOfWeek), 5)) \n )\n )\n )\n )\n )\n }\n }\n \n})/code>/pre>\n\n\n\np>Copy the query into the command panel, and click the Run Query button:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754701//08.02-create-manager-role-2.png?ssl1 alt classwp-image-304222 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754701//08.02-create-manager-role-2.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1273/v1582754701//08.02-create-manager-role-2.png 1273w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_785/v1582754701//08.02-create-manager-role-2.png 785w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754701//08.02-create-manager-role-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>At this point, we have created all of the necessary elements for implementing and trying out our example use case! Let’s continue with verifying that the access rules we just created are working as expected.../p>\n\n\n\nh3>Putting everything in action/h3>\n\n\n\np>Let’s start by checking the first rule: /p>\n\n\n\np>em>“Allow employee users to read public files only.”/em>/p>\n\n\n\np>The first thing we need to do is log in as an employee user so that we can verify which files can be read on its behalf. In order to do so, execute the following mutation from the GraphQL Playground console:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>mutation LoginEmployeeUser {\n loginUser(input: {\n username: peter.gibbons\n password: abcdef\n })\n}/code>/pre>\n\n\n\np>As a response, you should get a em>secret/em> access token. The secret represents that the user has been authenticated successfully:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754700//13-login-employee.png?ssl1 alt classwp-image-304223 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754700//13-login-employee.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1379/v1582754700//13-login-employee.png 1379w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1078/v1582754700//13-login-employee.png 1078w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_647/v1582754700//13-login-employee.png 647w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754700//13-login-employee.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>At this point, it’s important to remember that the access rules we defined earlier are not directly associated with the secret that is generated as a result of the login process. Unlike other authorization models, the secret token itself does not contain any em>authorization/em> information on its own, but it’s just an em>authentication/em> representation of a given document./p>\n\n\n\np>As explained before, access rules are stored in roles, and roles are associated with documents through their membership configuration. After authentication, the secret token can be used in subsequent requests to prove the caller’s identity and determine which roles are associated with it. This means that access rules are effectively verified in every subsequent request and not only during authentication. This model enables us to modify access rules dynamically without requiring users to authenticate again./p>\n\n\n\np>Now, we will use the secret issued in the previous step to validate the identity of the caller in our next query. In order to do so, we need to include the secret as a a hrefhttps://docs.fauna.com/fauna/current/api/graphql/endpoints#bearer-token>em>Bearer Token/em>/a> as part of the request. To achieve this, we have to modify the code>Authorization/code> header value set by the GraphQL Playground. Since we don’t want to miss the admin secret that is being used as default, we’re going to do this in a new tab./p>\n\n\n\np>Click the plus (code>+/code>) button to create a new tab, and select the code>HTTP HEADERS/code> panel on the bottom left corner of the GraphQL Playground editor. Then, modify the value of the Authorization header to include the secret obtained earlier, as shown in the following example. Make sure to change the em>scheme/em> value from Basic to Bearer as well:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>{\n authorization: Bearer fnEDdByZ5JACFANyg5uLcAISAtUY6TKlIIb2JnZhkjU-SWEaino\n}/code>/pre>\n\n\n\np>With the secret properly set in the request, let’s try to read all of the files on behalf of the employee user. Run the following query from the GraphQL Playground: /p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>query ReadFiles {\n allFiles {\n data {\n content\n confidential\n }\n }\n}/code>/pre>\n\n\n\np>In the response, you should see the public file only:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754700//14-read-files-employeee.png?ssl1 alt classwp-image-304224 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754700//14-read-files-employeee.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1398/v1582754700//14-read-files-employeee.png 1398w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1078/v1582754700//14-read-files-employeee.png 1078w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_654/v1582754700//14-read-files-employeee.png 654w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754700//14-read-files-employeee.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Since the role we defined for employee users does not allow them to read confidential files, they have been correctly filtered out from the response!/p>\n\n\n\np>Let’s move on now to verifying our second rule:/p>\n\n\n\np>em>“Allow manager users to read both public files and, only during weekdays, confidential files.”/em>/p>\n\n\n\np>This time, we are going to log in as the employee user. Since the login mutation requires an em>admin/em> secret token, we have to go back first to the original tab containing the default authorization configuration. Once there, run the following query:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>mutation LoginManagerUser {\n loginUser(input: {\n username: bill.lumbergh\n password: 123456\n })\n}/code>/pre>\n\n\n\np>You should get a new secret as a response:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754699//15-login-manager.png?ssl1 alt classwp-image-304225 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754699//15-login-manager.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1290/v1582754699//15-login-manager.png 1290w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1033/v1582754699//15-login-manager.png 1033w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_627/v1582754699//15-login-manager.png 627w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754699//15-login-manager.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Copy the secret, create a new tab, and modify the code>Authorization/code> header to include the secret as a Bearer Token as we did before. Then, run the following query in order to read all of the files on behalf of the manager user:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>query ReadFiles {\n allFiles {\n data {\n content\n confidential\n }\n }\n}/code>/pre>\n\n\n\np>As long as you’re running this query on a weekday (if not, feel free to update this rule to include weekends), you should be getting both the public and the confidential file in the response:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754698//16-read-files-manager.png?ssl1 alt classwp-image-304226 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754698//16-read-files-manager.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1305/v1582754698//16-read-files-manager.png 1305w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1003/v1582754698//16-read-files-manager.png 1003w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_610/v1582754698//16-read-files-manager.png 610w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754698//16-read-files-manager.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>And, finally, we have verified that all of the access rules are working successfully from the GraphQL API!/p>\n\n\n\nh3>Conclusion/h3>\n\n\n\np>In this post, we have learned how a comprehensive authorization model can be implemented on top of the a hrefhttps://synd.co/2SVX2zq>FaunaDB/a> GraphQL API using FaunaDB\s built-in ABAC features. We have also reviewed ABAC\s distinctive capabilities, which allow defining complex access rules based on the attributes of each system component./p>\n\n\n\np>While access rules can only be defined through the FQL API at the moment, they are effectively verified for every request executed against the FaunaDB GraphQL API. Providing support for specifying access rules as part of the GraphQL schema definition is already planned for the future./p>\n\n\n\np>In short, a hrefhttps://synd.co/2SVX2zq>FaunaDB/a> provides a powerful mechanism for defining complex access rules on top of the GraphQL API covering most common use cases without the need for third-party services./p>\n,protected:e}},{id:303379,slug:responsive-grid-magazine-layout-in-just-20-lines-of-css,title:{rendered:Responsive Grid Magazine Layout in Just 20 Lines of CSS},excerpt:{rendered:p>I was recently working on a modern take of the blogroll. The idea was to offer readers a selection of latest posts from those blogs in a magazine-style layout, instead of just popping a list of our favorite blogs in the sidebar. The easy part was grabbing a list of posts with excerpts from our …/p>\n,protected:e},date:2020-02-25T08:15:40,tags:686,1556,content:{rendered:\np>I was recently working on a modern take of the blogroll. The idea was to offer readers a selection of latest posts from those blogs in a magazine-style layout, instead of just popping a list of our favorite blogs in the sidebar./p>\n\n\n\np>The easy part was grabbing a list of posts with excerpts from our favorite RSS feeds. For that, we used a WordPress plugin, a hrefhttps://en-gb.wordpress.org/plugins/feedzy-rss-feeds/>Feedzy lite/a>, which can aggregate multiple feeds into a single time-ordered list — perfect for showcasing their latest offerings. The hard part was making it all look awesome./p>\n\n\n\n\x3c!--more--\x3e\n\n\n\np>The plugin’s default list UI is rather bland, so I wanted to style it to look like a newspaper or magazine website with a mixture of smaller and larger “featured content” panels./p>\n\n\n\np>This seems like an ideal case for CSS Grid! Create a grid layout for different layouts, say, one five-column layout and one three-column layout, then use media queries to switch between them at different break points. Right? But do we actually need those media queries — and all the hassle of identifying break points — when we can use grid’s code>auto-fit/code> options to automatically create a fluid responsive grid for us? /p>\n\n\n\np>The approach sounded tempting, but when I started introducing column-spanning elements, I ran into trouble with the grid overflowing on narrow screens. Media queries appeared to be the only solution. That is, until I found a workaround!/p>\n\n\n\np>After looking at several tutorials on CSS Grid, I found that they largely fall into two camps:/p>\n\n\n\nol>li>Tutorials that show you how to create an interesting layout with spanned elements, but for a fixed number of columns./li>li>Tutorials that explain how to make a responsive grid that resizes automatically, but with all of the grid items the same width (i.e. without any spanned columns)./li>/ol>\n\n\n\np>I want to make the grid do both: create a fully responsive fluid layout that includes responsively resizing multi-column elements as well./p>\n\n\n\np>The beauty is that once you understand the limitations of responsive grids, and why and when column spans break grid responsiveness, it is possible to define a responsive magazine/news style layout in just strong>a dozen lines of code/strong> plus one simple media query (or even with no media queries if you are willing to limit your span options)./p>\n\n\n\np>Here’s a visual showing the RSS plugin right out of the box and what it’ll look like after we style it up. /p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754915//min-grid-1.png?ssl1 alt classwp-image-303380 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1668/v1582754915//min-grid-1.png 1668w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1383/v1582754915//min-grid-1.png 1383w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1085/v1582754915//min-grid-1.png 1085w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_706/v1582754915//min-grid-1.png 706w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754915//min-grid-1.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>(a relnoreferrer noopener target_blank hrefhttps://rosemarycottageclinic.co.uk/blog/world-nutrition-news/>Demo/a>)/figcaption>/figure>\n\n\n\np>This magazine-style grid layout is fully responsive with the colored featured panels adjusting dynamically as the number of columns change. The page displays around 50 posts, but the layout code is agnostic as to the number of items displayed. Ramp up the plugin to show 100 items and the layout stays interesting all the way down./p>\n\n\n\np>All of this is achieved using only CSS and with only a single media query to deal with a single column display on the narrowest of screens (i.e. smaller than 460px)./p>\n\n\n\np>Incredibly, this layout only took 21 lines of CSS (excluding global content styling). However, to achieve such flexibility in such a few lines of code, I had to dig deep into the more obscure parts of some of CSS Grid and learn how to work around some of its inherent limitations./p>\n\n\n\np>The essential elements of the code that produce this layout is incredibly short and a testament to the awesomeness of CSS Grid:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.archive {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));\n grid-gap: 32px;\n grid-auto-flow: dense;\n}\n\n/* Extra-wide grid-posts */\n.article:nth-child(31n + 1) {\n grid-column: 1 / -1;\n}\n.article:nth-child(16n + 2) {\n grid-column: -3 / -1;\n}\n.article:nth-child(16n + 10) {\n grid-column: 1 / -2;\n}\n\n/* Single column display for phones */\n@media (max-width: 459px) {\n .archive {\n display: flex;\n flex-direction: column;\n }\n}/code>/pre>\n\n\n\np>The techniques in this article could be used equally well to style any dynamically generated content such as the output from a latest posts widget, archive pages or search results./p>\n\n\n\nh3>Creating a responsive grid/h3>\n\n\n\np>I have set up seventeen items displaying a variety of mock content — headlines, images and excerpts — which are all contained in a wrapper/p>\n\n\n\npre relHTML classwp-block-csstricks-code-block language-markup data-line>code markuptt><div classarchive>\n <article classarticle>\n <!-- content --\x3e\n </article>\n \n <!-- 16 more articles --\x3e\n \n</div>/code>/pre>\n\n\n\np>The code that turns these items into a responsive grid is remarkably compact:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.archive {\n /* Define the element as a grid container */\n display: grid;\n /* Auto-fit as many items on a row as possible without going under 180px */\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n /* A little spacing between articles */\n grid-gap: 1em;\n}/code>/pre>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_xxbjjOJ src//codepen.io/anon/embed/xxbjjOJ?height500&theme-id1&slug-hashxxbjjOJ&default-tabresult height500 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed xxbjjOJ titleCodePen Embed xxbjjOJ classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>Notice how the heights of the rows automatically adjust to accommodate the tallest content in the row. If you change the width of the Pen, you will see the items grow and shrink fluidly and the number of columns change from one to five, respectively./p>\n\n\n\np>The CSS Grid magic at play here is the code>auto-fit/code> keyword that works hand-in-hand with the code>minmax()/code> function that’s applied to code>grid-template-columns/code>./p>\n\n\n\nh3>How it works/h3>\n\n\n\np>We could have achieved the five-column layout alone using this:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.archive {\n display: grid;\n grid-template-columns: repeat(5, 1fr);\n}/code>/pre>\n\n\n\np>However, this would create five columns that grow and shrink with different screen widths, but always stay at five columns, resulting in them becoming ridiculously narrow on small screens. The first thought might be to create a bunch of media queries and redefine the grid with different numbers of columns. That would work fine, but with the code>auto-fit/code> keyword, it is all done automatically./p>\n\n\n\np>For auto-fit to work the way we want, we need to use the code>minmax()/code> function. This tells the browser how small the columns can be squeezed down to followed by the maximum width they can expand to. Any smaller, and it will automatically reduce the number of columns. Any larger, and the number of columns increases./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.archive {\n grid-template-columns: repeat (auto-fit, minmax(180px, 1fr));\n}/code>/pre>\n\n\n\np>In this example, the browser will fit in as many columns as it can 180px wide. If there is space left over the columns will all grow equally by sharing the remaining space between them — that’s what the code>1fr/code> value is saying: make the columns equal fractions of the available width. /p>\n\n\n\np>Drag the window out and as the available space increases the columns all grow equally to use up any additional space. The columns will keep growing until the available space allows for an additional 180px column, at which point a whole new column appears. Decrease the screen width, and the process reverses, perfectly adjusting the grid all the way down to a single column layout. Magic!/p>\n\n\n\nfigure>video srchttps://res.cloudinary.com/css-tricks/video/upload/v1582754963//responsive-grid-no-mqs.mov controls>/video>/figure>\n\n\n\np>And you get all this responsiveness out of just one line of code. How cool is that? /p>\n\n\n\nh3>Creating spans with “autoflow: dense”/h3>\n\n\n\np>So far, we have a responsive grid but all items the same width. For a news or magazine layout we need some content to be featured by spanning two or more columns or even, perhaps, to span all the columns./p>\n\n\n\np>To create multi-column spans we can add the column-span feature to the grid items we want to take up more space. For example, if we want the third item in our list to be two columns wide we can add:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.article:nth-child(3) {\n grid-column: span 2;\n}/code>/pre>\n\n\n\np>However, once we start adding spans a number of problems can arise. First, gaps may appear in the grid because a wide item may may not fit on the row, so grid code>auto-fit/code> pushes it onto the next line, leaving a gap where it would have been:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754921//Responsive-Grid.png?ssl1 alt classwp-image-303462 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1275/v1582754921//Responsive-Grid.png 1275w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754921//Responsive-Grid.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>The easy fix is adding code>grid-auto-flow: dense/code> to the grid element which tells the browser to fill in any gaps with other items, effectively making the narrower content flow around the wider items like this:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754924//Responsive-Grid-Auto-Flow.png?ssl1 alt classwp-image-303463 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1275/v1582754924//Responsive-Grid-Auto-Flow.png 1275w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1083/v1582754924//Responsive-Grid-Auto-Flow.png 1083w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754924//Responsive-Grid-Auto-Flow.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Note that the items are now out of order, with the fourth item coming before the third item, which is double the width. There is no way round this as far as I can tell, and it is one of the limitations you have to accept with CSS Grid./p>\n\n\n\np classexplanation>Check out Geoff Graham’s a hrefhttp://(https//css-tricks.com/the-auto-flowing-powers-of-grids-dense-keyword/>The Auto-Flowing Powers of Grid’s Dense Keyword”/a> for an introduction to grid-auto-flow: dense with examples of how it behaves./p>\n\n\n\nh3>Ways to specify spans/h3>\n\n\n\np>There are several ways to indicate how many columns an item should span. The easiest is to apply code>grid-columns: span n/code> to one of the items, where code>n/code> is the number of columns the element will span. The third item in our layout has code>grid-column: span 2/code>, which explains why it is double the width of other items that only span a single column./p>\n\n\n\np>Other methods require you to a hrefhttps://css-tricks.com/things-ive-learned-css-grid-layout/%23article-header-id-3>explicitly define grid lines/a>. The numbering system for grid lines is as follows:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754926//gridin-04.png?ssl1 alt classwp-image-303385 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1594/v1582754926//gridin-04.png 1594w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_960/v1582754926//gridin-04.png 960w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754926//gridin-04.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Grid lines can be specified from left-to-right using positive values (e.g. 1, 2, 3) or negative values (e.g. -1, -2, -3) to go from right-to-left. These can be used to place items on the grid using the grid-column property like this:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.grid-item {\n grid-column: (start track) / (end track);\n}/code>/pre>\n\n\n\np>So, this gives us additional ways to specify a spanned item. This is especially flexible as either the start or end value can be replaced with the span keyword. For example, the three-column blue box in the example above could be created by adding any of the following to the eighth grid item:/p>\n\n\n\nul>li>code>grid-column: 3 / 6/code>/li>li>code>grid-column: -4 / -1/code>/li>li>code>grid-column: 3 / span 3/code>/li>li>code>grid-column: -4 / span 3/code>/li>li>code>grid-column: span 3 / -1/code>/li>li>Etc./li>/ul>\n\n\n\np>On a non-responsive (i.e. fixed columns) grid, these all produce the same effect (like the blue box above), however, if the grid is responsive and the number of columns changes, their differences start to become apparent. Certain column spans break the layout with an auto-flowing grid, making the two techniques appear incompatible. Fortunately, there are some solutions which allow us to combine the two successfully. /p>\n\n\n\np>First, however, we need to understand the problem./p>\n\n\n\nh3>Overflow side-scrolling problems/h3>\n\n\n\np>Here are some featured areas created using the notation above:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754931//gridmin-05.png?ssl1 alt classwp-image-303386 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1654/v1582754931//gridmin-05.png 1654w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1497/v1582754931//gridmin-05.png 1497w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_953/v1582754931//gridmin-05.png 953w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754931//gridmin-05.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>strong>(/strong>a relnoreferrer noopener target_blank hrefhttps://codepen.io/Everybodyknows/pen/xxbjPQp>Demo/a>)/figcaption>/figure>\n\n\n\np>It all looks good at full-width (five columns) but when resized to what should be two columns, the layout breaks like this:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754936//gridmin-07.png?ssl1 alt classwp-image-303388 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1840/v1582754936//gridmin-07.png 1840w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1490/v1582754936//gridmin-07.png 1490w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754936//gridmin-07.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np> As you can see, our grid has lost its responsiveness and, although the container has shrunk, the grid is trying to maintain all five columns. To do so, it has given up trying to keep equal-width columns, and the grid is breaking out of the right-hand side of its container, causing horizontal scrolling./p>\n\n\n\np>Why is this? The problem comes about because the browser is trying to honor the explicit grid lines we named. At this width, the code>auto-fit/code> grid should implicitly be displaying two columns, but our grid line numbering system contradicts this by explicitly referring to the fifth grid line. This contradiction leads to the mess. To display our implicit two-column grid correctly, the only line numbers allowed are 1, 2 and 3 and -3, -2, -1, like this:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754941//gridmin-06.png?ssl1 alt classwp-image-303387 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1044/v1582754941//gridmin-06.png 1044w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754941//gridmin-06.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>But if any of our grid items contains code>grid-column/code> references that lie outside this, such as grid line number 4, 5 or 6 (or -4, -5 or -6), the browser is getting mixed messages. On the one hand, we have asked it to automatic create flexible columns (which should implicitly give us two columns at this screen width) but we have also explicitly referred to grid lines that don’t appear in a two-column grid. When there is a conflict between implicit (automatic) columns and an explicit number of columns, strong>grid always defers to the explicit grid/strong>; hence the unwanted columns and horizontal overflow (which has also been aptly named a hrefhttps://css-tricks.com/overflow-and-data-loss-in-css/>CSS data loss/a>). Just like using grid line numbers, spans can also create explicit columns. So, code>grid-column: span 3/code> (the eighth grid item in the demo) forces the grid to explicitly adopt at least three columns, whereas we want it, implicitly display two./p>\n\n\n\np>At this point it might seem like the only way forward is to use media queries to change the grid-column values at the width where our layout breaks — but not so fast! That’s what I assumed at first. But after thinking it though a bit more and playing around with various options, I found there are a limited set of workarounds that work all the way down to two columns, leaving just one media query to cover a single column layout for the narrowest screens./p>\n\n\n\nh3>The solutions/h3>\n\n\n\np>The trick, I realized, is to only specify spans using grid lines that appear in the narrowest grid you intend to display. That is a two-column grid in this case. (We will use a media query to cover the single column scenario for very narrow screens.) That means we can safely use grid lines 1, 2 and 3 (or -3, -2 and -1) without breaking the grid./p>\n\n\n\np>I initially thought that meant limiting myself to a maximum span of two columns, using combinations of the following:/p>\n\n\n\nul>li>code>grid column: span 2/code>/li>li>code>grid-column: 1 /3/code>/li>li>code>grid-column: -3 / -1/code>/li>/ul>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754943//gridmin-08.png?ssl1 alt classwp-image-303389 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754943//gridmin-08.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1001/v1582754943//gridmin-08.png 1001w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754943//gridmin-08.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Which remains perfectly responsive right down to two columns:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754947//gridmin-09.png?ssl1 alt classwp-image-303390 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1600/v1582754947//gridmin-09.png 1600w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1282/v1582754947//gridmin-09.png 1282w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754947//gridmin-09.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>a hrefhttps://codepen.io/Everybodyknows/pen/dyPegoo>Although this works/a>, it is rather limiting from a design perspective, and not particularly exciting. I wanted to be able to create spans that would be three, four or even five columns wide on large screens. But how? My first thought was that I would have to resort to media queries (OMG old habits die hard!) but I was trying to get away from that approach and think differently about responsive design./p>\n\n\n\np>Taking another look at what we can do with just 1 to 3 and -3 to -1, I gradually realized that I could mix positive and negative line numbers for the grid column’s start and end values ,such as code>1/-3/code> and code>2/-2/code>. At first glance, this does not seem very interesting. That changes when you realize where these lines are located as you resize the grid: these spanned elements change width with the screen size. This opened up a whole new set of possibilities for responsive column spans: items that will span different numbers of columns as the screen gets wider, without needing media queries./p>\n\n\n\np>The first example I discovered is grid-column: code>1/-1/code>.This makes the item act like a full-width banner, spanning from the first to the last column at all column numbers. it even works down to one column wide!/p>\n\n\n\np>By using code>grid-column: 1/-2/code>, a left-aligned nearly-full-width span could be created that would always leave a one column item to the right of it. When shrunk to two columns it would shrink responsively to a single column. Surprisingly, it even works when shrunk to a single column layout. (The reason seems to be that grid will not collapse an item to zero width, so it remains one column wide, as does code>grid-column: 1/1/code>.) I assumed code>grid-column: 2/-1/code> would work similarly, but aligned with the right-hand edge, and for the most part it does, except at one column display when it causes overflow./p>\n\n\n\np>Next I tried code>1/-3/code> which worked fine on wider screen, showing at least three columns, and smaller screens, showing one column. I thought it would do something weird on a two-column grid as the first grid line is the same as the grid line with code>-3/code>. To my surprise, it still displays fine as a single-column item. /p>\n\n\n\np>After a lot of playing around, I came up with eleven possible grid column values using grid line numbers from the two-column grid. Surprisingly, three of these work right down to single-column layouts. Seven more work down to two columns and would only need a single media query to deal with single column display./p>\n\n\n\np>Here is the full list:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754950//gridmin-10.png?ssl1 alt classwp-image-303391 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1042/v1582754950//gridmin-10.png 1042w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754950//gridmin-10.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Responsive grid-column values, showing how they display at different screen sizes in an code>auto-fit/code> grid. (a relnoreferrer noopener target_blank hrefhttps://codepen.io/Everybodyknows/full/QWwZGdE>Demo/a>)/figcaption>/figure>\n\n\n\np>As you can see, although this is a limited subset of every possible responsive span, there are actually a lot of possibilities./p>\n\n\n\nul>li>code>2/-2/code> is interesting as it creates a centered span which works all the way down to one column! /li>li>code>3/-1/code> is least useful as it causes overflow even with two-columns./li>li>code>3/-3/code> was a surprise./li>/ul>\n\n\n\np>By using a variety of code>grid-column/code> values from this list, it is possible to create an interesting and fully responsive layout. Using a single media query for the narrowest single-column display, we have ten different code>grid-column/code> span patterns to play with. /p>\n\n\n\np>The single-column media query is generally straightforward as well. The one on this final demo reverts to using flexbox at smaller screens:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>@media (max-width: 680px) {\n .archive {\n display: flex;\n flex-direction: column;\n }\n\n .article {\n margin-bottom: 2em;\n }\n}/code>/pre>\n\n\n\np>Here is the final grid which, as you can see, is fully responsive from one to five columns:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/css-tricks.com/wp-content/uploads/2020/02/gridmin-11.gif?ssl1 alt classwp-image-303392 data-recalc-dims1/>figcaption>(a relnoreferrer noopener target_blank hrefhttps://codepen.io/Everybodyknows/full/RwNyeoo>Demo/a>)/figcaption>/figure>\n\n\n\nh3>Using :nth-child() to repeat variable length displays/h3>\n\n\n\np>The last trick I used to get my code down to two dozen lines was the code>:nth-child(n)/code> selector which I used to style multiple items in my grid. I wanted my span styling to apply to multiple items in my feed, so that the featured post boxes appeared regularly throughout the page. To start with I used a comma-separated selector list, like this:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.article:nth-child(2),\n.article:nth-child(18),\n.article:nth-child(34),\n.article:nth-child(50) {\n background-color: rgba(128,0,64,0.8);\n grid-column: -3 / -1;\n}/code>/pre>\n\n\n\np>But I soon found this cumbersome, especially as I had to repeat this list for each child element I wanted to style within each article — such as the title, links and so on. During prototyping, if I wanted to play around with the position of my spanned elements, I had to manually change the numbers in each of these lists, which was tedious and error-prone./p>\n\n\n\np>That’s when I realized that I could use a powerful feature code>:nth-child/code> pseudo-selector instead of a simple integer as I had used in the list above. code>:nth-child(n)/code> can also take an equation, such as code>:nth-child(2n+ 2)/code>strong>,/strong> which will target every second child element./p>\n\n\n\np>Here is how I used the code>:nth-child(formula)/code> to create the blue full-width panels in my grid which appear at the very top of the page, and is repeated just over half way down:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.article:nth-child(31n + 1) {\n grid-column: 1 / -1;\n background: rgba(11, 111, 222, 0.5);\n}/code>/pre>\n\n\n\np>The bit in the brackets (code>31n + 1/code> ) ensures that the 1sup>st/sup>, 32sup>nd/sup>, 63sup>rd/sup>, etc. child is selected. The browser runs a loop starting with n0 (in which case code>31 * 0 + 1 1/code>), then code>n1/code> (code>31 * 1 + 1 32/code>), then code>n2/code> (code>31 * 2 + 1 63/code>). In the last case, the browser realizes that there is no 63sup>rd/sup> child item so it ignores that, stops looping, and applies the CSS to the 1sup>st/sup> and 32sup>nd/sup> children./p>\n\n\n\np>I do something similar for the purple boxes which alternate down the page from right-to-left:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.article:nth-child(16n + 2) {\n grid-column: -3 / -1;\n background: rgba(128, 0, 64, 0.8);\n}\n\n.article:nth-child(16n + 10) {\n grid-column: 1 / -2;\n background: rgba(128, 0, 64, 0.8);\n}/code>/pre>\n\n\n\np>The first selector is for the right-hand purple boxes. The code>16n + 2/code> makes sure that the styling applies to every 16sup>th/sup> grid item, starting with the second item./p>\n\n\n\np>The second selector targets the right-hand boxes. It uses the same spacing (code>16n/code>) but with a different offset (code>10/code>). As a result, these boxes appear regularly on the right-hand side for grid items 10, 26, 42, etc./p>\n\n\n\np>When it comes to the visual styling for these grid items and their contents, I used another trick to reduce repetition. For styles that both boxes share (such as the code>background-color/code>, for example) a single selector can be used to target both:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.article:nth-child(8n + 2) {\n background: rgba(128, 0, 64, 0.8);\n /* Other shared syling */\n}/code>/pre>\n\n\n\np>This will target items 2, 10, 18, 26, 34, 42, 50, and so forth. In other words, it selects both the left- and right-hand featured boxes./p>\n\n\n\np>It works because 8n is exactly half of code>16n/code>, and because the offsets used in the two separate selectors have a difference of 8 (i.e. the difference between +10 and +2 is 8) /p>\n\n\n\nh3>Final thoughts/h3>\n\n\n\np>Right now, CSS Grid can be used to create flexible responsive grids with minimal code, but this does come with some significant limitations on positioning elements without the retrograde step of using media queries./p>\n\n\n\np>It would be great to be able to specify spans that would not force overflow on smaller screens. At the moment, we effectively tell the browser, “Make a responsive grid, please,” which it does beautifully. But when we continue by saying, “Oh, and make this grid item span four columns,” it throws a hissy-fit on narrow screens, prioritizing the four-column span request rather than the responsive grid. It would be great to be able to tell grid to prioritize responsiveness over our span request. Something like this:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.article {\n grid-column: span 3, autofit;\n}/code>/pre>\n\n\n\np>Another issue with responsive grids is the last row. As the screen width changes the last row will frequently not be filled. I spent a long time looking for a way to make the last grid item span (and hence fill) the remaining columns, but it seems you can’t do it in Grid right now. It would be nice if we could specify the item’s start position with a keyword like auto meaning, “Please leave the left-hand edge wherever it falls.” Like this:/p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>.article {\n grid-column: auto, -1;\n}/code>/pre>\n\n\n\np>…which would make the left-hand edge span to the end of the row./p>\n,protected:e}},{id:302244,slug:recreating-the-codepen-gutenberg-embed-block-for-sanity-io,title:{rendered:Recreating the CodePen Gutenberg Embed Block for Sanity.io},excerpt:{rendered:p>Learn how to create a custom CodePen block with a preview for Sanity Studio, inspired by Chris Coyier’s implementation for Wordpress’ Gutenberg editor./p>\n,protected:e},date:2020-02-24T18:44:56,tags:425,605,content:{rendered:\np>Chris recently put out a neat a hrefhttps://wordpress.org/plugins/codepen-embed-block/>CodePen Embed Block for the Gutenberg editor in WordPress/a>. It allows you to embed a Pen just by dropping in its URL. From there, you get access to control the size, theme, and the default tabs that render on initial load. Super neat!/p>\n\n\n\n\x3c!--more--\x3e\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755289//Screen-Shot-2020-01-28-at-4.57.06-PM.png?ssl1 alt classwp-image-302896 srcsethttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755289//Screen-Shot-2020-01-28-at-4.57.06-PM.png?ssl1 2506w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_2048/v1582755289//Screen-Shot-2020-01-28-at-4.57.06-PM.png 2048w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1793/v1582755289//Screen-Shot-2020-01-28-at-4.57.06-PM.png 1793w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1497/v1582755289//Screen-Shot-2020-01-28-at-4.57.06-PM.png 1497w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1076/v1582755289//Screen-Shot-2020-01-28-at-4.57.06-PM.png 1076w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755289//Screen-Shot-2020-01-28-at-4.57.06-PM.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Having a live preview of the embedded Pen while writing is so handy!/figcaption>/figure>\n\n\n\np>But it got me thinking: How difficult would it be to recreate it with a hrefhttps://www.sanity.io/studio>Sanity Studio’s Portable Text editor/a>? (Spoiler: Not that difficult). Since I already knew how to do it, it took me under seven minutes from start to finish. This tutorial takes you through how to get up and running with a studio, and how to add the schemas and the custom preview component for a CodePen embed./p>\n\n\n\nblockquote classtwitter-tweet>p langen dirltr>So this is me recreating a hrefhttps://twitter.com/chriscoyier?ref_srctwsrc%5Etfw>@chriscoyier/a>’s CodePen Gutenberg Block for a hrefhttps://twitter.com/sanity_io?ref_srctwsrc%5Etfw>@sanity_io/a>’s rich text editor in less than 7min (3x video). Best thing is, you actually just store the structured data, making it queryable, future proof, and easy to integrate with whatever frontend you prefer. a hrefhttps://t.co/psPn6NtPjz>https://t.co/psPn6NtPjz/a> a hrefhttps://t.co/6aSGKerHfO>pic.twitter.com/6aSGKerHfO/a>/p>— knut (in SF 🇺🇸) (@kmelve) a hrefhttps://twitter.com/kmelve/status/1218610296446582784?ref_srctwsrc%5Etfw>January 18, 2020/a>/blockquote> script async srchttps://platform.twitter.com/widgets.js charsetutf-8>\/script>\n\n\n\np>That felt so cool that I want to teach you how to do it as well. Let\s dive right into it./p>\n\n\n\nh2>Getting Sanity Studio up and running locally/h2>\n\n\n\np>First, you\ll need to install Sanity Studio locally on your machine. In this tutorial we will be using the blog studio that you can initiate from the command line, but you can also check out the different starters on a hrefhttps://www.sanity.io/create>sanity.io/create/a>. You should be able to tag along with one of those too./p>\n\n\n\np>This tutorial assumes that you have a bit of knowledge of JavaScript. It will use a bit of React, but only a small part. You should have a hrefhttps://github.com/nvm-sh/nvm>installed node and npm/a> if you haven\t already./p>\n\n\n\np>Oh, and you\ll want the Sanity CLI, which you can snag with the command line:/p>\n\n\n\npre relTerminal classlanguage-none data-line classwp-block-csstricks-code-block>code markuptt>npm install --global @sanity/cli/code>/pre>\n\n\n\np>Once the installation is done, you can initiate a new Sanity Studio with a new project by running the command code>sanity init/code>. It will let you log in with your Google or GitHub account (or make a new account with an email/password). Give your project a name and follow the instructions. When given the options for a project template, choose the blog one:/p>\n\n\n\npre relTerminal classlanguage-none data-line classwp-block-csstricks-code-block>code markuptt>? Select project template\n Movie project (schema + sample data)\n E-commerce (schema + sample data)\n❯ Blog (schema)\n Clean project with no predefined schemas/code>/pre>\n\n\n\np>After completing the steps, change directory (code>cd/code>) into the new project folder and open it in your favorite code editor. To start the developer server that will also hot reload your studio when you make changes, run code>sanity start/code>. To stop this server, you press code>ctrl + C/code> in most command line tools./p>\n\n\n\nh2>Adding the schemas for a CodePen embed/h2>\n\n\n\np>Schemas define which document types that are available in the Studio, and which input fields they have. These schemas are defined in JavaScript objects that you import into the code>schemas.js/code> file, where they are exported as a function that the Studio translates into its UI. There\s a lot you can do with these schemas, but in this tutorial, we will keep it reasonably simple./p>\n\n\n\np>Start with adding a new file inside code>/yourproject/schemas/code> called code>codepen.js/code>. Then type in this code:/p>\n\n\n\npre relJSX classlanguage-jsx data-line classwp-block-csstricks-code-block>code markuptt>export default {\n name: codepen,\n type: object,\n title: CodePen Embed,\n fields: \n {\n name: url,\n type: url,\n title: CodePen URL\n }\n \n};/code>/pre>\n\n\n\np>Then you can go to code>/yourproject/schemas/schema.js/code> and add the following two lines of code to it:/p>\n\n\n\npre relJavaScript classlanguage-javascript data-line8,17 classwp-block-csstricks-code-block>code markuptt>import createSchema from part:@sanity/base/schema-creator;\nimport schemaTypes from all:part:@sanity/base/schema-type;\n\nimport blockContent from ./blockContent;\nimport category from ./category;\nimport post from ./post;\nimport author from ./author;\nimport codepen from /codepen.js; // first import the object\n\nexport default createSchema({\n name: default,\n types: schemaTypes.concat(\n post,\n author,\n category,\n blockContent,\n codepen // add it to the schema types array\n )\n});/code>/pre>\n\n\n\np>So what did we just do? Well, we have now made this CodePen object available as a code>type/code> in other schemas in the Studio. In other words, you can now add code>type: \codepen\/code> to get those fields anywhere else in the schema code where you add fields. Adding this type to the rich text field is also our next step. Hang on!/p>\n\n\n\nh3>Adding the CodePen field to the rich text editor/h3>\n\n\n\np>Before diving into the code bit, let us take a step back and look at what is going on in terms of the data formats we operate with, and how WordPress and Sanity differ slightly./p>\n\n\n\np>While Gutenberg stores rich text as JSON in its runtime (which is great!), what developers end up dealing with is mostly this content as HTML and JSON objects inside of HTML comments./p>\n\n\n\np>Sanity stores and distributes rich text content as a hrefhttps://www.portabletext.org/>Portable Text/a>, which developers then serializes in their frontends. That means that you get fine-grained control over how rich text content is rendered by letting you use custom components for your favorite framework, either it\s a hrefhttps://github.com/sanity-io/block-content-to-react>React/a>, a hrefhttps://github.com/rdunk/sanity-blocks-vue-component>Vue/a>, a hrefhttps://github.com/movingbrands/svelte-portable-text>Svelte/a>, or a hrefhttps://github.com/oslofjord/sanity-linq#9-rendering-block-content>.NET/a>, a hrefhttps://github.com/sanity-io/sanity-php#rendering-block-content>PHP/a>, or even a hrefhttps://github.com/sanity-io/block-content-to-markdown>Markdown/a>./p>\n\n\n\np>In other words, you store your content as em>structured data/em> in Sanity’s backend, and then decide how you want to use the data inside your frontend components. But enough exposition, let\s get back to the code!/p>\n\n\n\np>Open code>/schemas/blockContent.js/code> and notice that it\s of the type code>array/code>. Yes, rich text is an array of different types, where one of them has to be of the code>block/code> type (in which text paragraphs are stored). So the simplest way of making rich text is the following schema definition:/p>\n\n\n\npre relJSX classlanguage-jsx data-line classwp-block-csstricks-code-block>code markuptt>export default {\n name: body,\n type: array,\n title: Body,\n of: \n {\n type: block\n }\n \n};/code>/pre>\n\n\n\np>Now, code>blockContent.js/code> has a bunch of more stuff. You can see code>styles/code>, code>lists/code>, code>marks/code>, and so on. All defining which properties should be available for the author. In the top array, there are two types code>block/code> and code>image/code>. We are going to add the third one, code>codepen/code>:/p>\n\n\n\npre relJSX classlanguage-jsx data-line classwp-block-csstricks-code-block>code markuptt>export default {\n title: Block Content,\n name: blockContent,\n type: array,\n of: \n {\n type: block\n // ...\n },\n {\n type: image,\n options: { hotspot: true }\n },\n {\n type: codepen\n }\n \n};/code>/pre>\n\n\n\np>Save the file, and that\s it! If you now run code>sanity start/code> in your command line (assuming you haven\t already), and open the Studio on code>https://localhost:3333/code>, you should be able to find your new field in the rich text editor under the post type:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755301//codepen-1.png?ssl1 altSanity Studio with a CodePen button in the Rich Text editor. classwp-image-302245 srcsethttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755301//codepen-1.png?ssl1 2400w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_2048/v1582755301//codepen-1.png 2048w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1556/v1582755301//codepen-1.png 1556w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1081/v1582755301//codepen-1.png 1081w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755301//codepen-1.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>If you try out the new button, you\ll get a modal with the URL field that you defined in the previous section. Feel free to add the URL from a cool CodePen that you have found. We will use this one from the legendary Sara Drasner; it\s pretty cool./p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_gWWQgb src//codepen.io/anon/embed/gWWQgb?height450&theme-id1&slug-hashgWWQgb&default-tabresult height450 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed gWWQgb titleCodePen Embed gWWQgb classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>Just showing the URL value in the editor isn\t especially inspiring, though. So let\s go ahead and add the actual CodePen embed so we can interact with it directly in the editor!/p>\n\n\n\nh2>Adding the CodePen embed as a preview/h2>\n\n\n\np>Open code>/yourproject/schemas/codepen.js/code> again. Now we are going to make a small React component for our preview. Start by importing React in the top, and the boilerplate for the React component that we will turn into the embed:/p>\n\n\n\npre relJSX classlanguage-jsx data-line classwp-block-csstricks-code-block>code markuptt>import React from react;\n\nconst CodePenPreview ({ value }) > {\n return <pre>{JSON.stringify(value, null, 2)}</pre>;\n};\n\nexport default {\n name: codepen,\n type: object,\n title: CodePen Embed,\n fields: \n {\n name: url,\n type: url,\n title: CodePen URL\n }\n \n};/code>/pre>\n\n\n\np>The code>JSON.stringify/code> stuff is a temporary little way of outputting the incoming data in a readable manner. You could also use code>console.log(value)/code>, but who has time to open the developer console?/p>\n\n\n\np>Now you must tell Sanity how to use this component for the preview. As well as which of the fields in the object it should code>select/code> for the code>value/code> in the preview component./p>\n\n\n\npre relJSX classlanguage-jsx data-line classwp-block-csstricks-code-block>code markuptt>import React from react;\n\nconst CodePenPreview ({ value }) > {\n return <pre>{JSON.stringify(value, null, 2)}</pre>;\n};\n\nexport default {\n name: codepen,\n type: object,\n title: CodePen Embed,\n preview: {\n select: {\n url: url\n },\n component: CodePenPreview\n },\n fields: \n {\n name: url,\n type: url,\n title: CodePen URL\n }\n \n};/code>/pre>\n\n\n\np>The editor should look something like this after you saved your changes:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755306//codepen-2.png?ssl1 alt classwp-image-302246 srcsethttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755306//codepen-2.png?ssl1 2400w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_2048/v1582755306//codepen-2.png 2048w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1895/v1582755306//codepen-2.png 1895w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1406/v1582755306//codepen-2.png 1406w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_906/v1582755306//codepen-2.png 906w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755306//codepen-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Cool! Now we want to take the code>url/code> value and somehow integrate it with a CodePen embed. The easiest way to go about this is to fit the markup for CodePen’s iFrame embed, and fit into our preview component in React./p>\n\n\n\np>The original iFrame element will look like this:/p>\n\n\n\npre relHTML classlanguage-markup data-line classwp-block-csstricks-code-block>code markuptt><iframe height265 stylewidth: 100%; scrollingno titleReact Animated Page Transitions srchttps://codepen.io/sdras/embed/gWWQgb?height265&theme-iddark&default-tabjs,result frameborderno allowtransparencytrue allowfullscreentrue>\n See the Pen <a href\https://codepen.io/sdras/pen/gWWQgb\>React Animated Page Transitions</a> by Sarah Drasner\n (<a href\https://codepen.io/sdras\>@sdras</a>) on <a href\https://codepen.io\>CodePen</a>.\n</iframe>/code>/pre>\n\n\n\np>If we paste this snippet into our preview component, it will em>almost/em> work. In order to make it a hrefhttps://reactjs.org/docs/introducing-jsx.html>JSX-compatible/a> you\ll have to some few changes to some of the HTML-attributes. Make sure that you change:/p>\n\n\n\nul>li>code>stylewidth: 100%;/code> to code>style{{width: 100%}}/code>/li>li>code>frameborderno/code> to code>frameBorderno/code>/li>li>code>allow-transparencytrue/code> to code>allowTransparency/code>/li>li>code>allow-fullscreentrue/code> to code>allowFullScreen/code>/li>/ul>\n\n\n\np>You can remove the content (links, etc.) inside of the iframe, because it isn\t particularly useful inside the studio. What we should end up with is something like this:/p>\n\n\n\npre relJSX classlanguage-jsx data-line classwp-block-csstricks-code-block>code markuptt>import React from react;\nimport Codepen from react-codepen-embed;\n\nconst CodePenPreview ({ value }) > {\n return (\n <iframe\n height265\n style{{ width: \100%\ }}\n scrollingno\n titleReact Animated Page Transitions\n srchttps://codepen.io/sdras/embed/gWWQgb?height370&theme-iddark&default-tabjs,result\n frameBorderno\n allowTransparency\n allowFullScreen\n />);\n};\n\n// .../code>/pre>\n\n\n\np>When saved, we should be able to see the CodePen embed inside the rich text editor:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755317//codepen-3.png?ssl1 alt classwp-image-302248 srcsethttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755317//codepen-3.png?ssl1 2400w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_2048/v1582755317//codepen-3.png 2048w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1722/v1582755317//codepen-3.png 1722w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1329/v1582755317//codepen-3.png 1329w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_868/v1582755317//codepen-3.png 868w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755317//codepen-3.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>Notice that the iFrame has an embed URL with some parameters for how it should be displayed. Of course, we could\ve asked someone to dive into CodePen to obtain this URL, but it\s probably better for to use the regular one. We\ll take the effort to reassemble into what we need:/p>\n\n\n\np>The last part is to take the URL from the field, and get the code>hash/code> and code>user/code> out of it. /p>\n\n\n\np>We split the URL string on forward slashes into an array. Then we use array destructuring to assign the different array elements to a variable. Since we only need the code>user/code> and the code>hash/code> we leave the other positions empty. This method isn\t bulletproof, as it assumed a specific format for the URL, but it works for this example. Then we reassemble the code>embedUrl/code> by using a hrefhttps://css-tricks.com/template-literals/>template literals/a>./p>\n\n\n\npre relJSX classlanguage-jsx data-line classwp-block-csstricks-code-block>code markuptt>import React from react;\n\nconst CodePenPreview ({ value }) > {\n const { url } value;\n const splitURL url.split(/);\n // \https:\, \\, \codepen.io\, \sdras\, \pen\, \gWWQgb\ \n const , , , user, , hash splitURL;\n const embedUrl `https://codepen.io/${user}/embed/${hash}?height370&theme-iddark&default-tabresult`;\n return (\n <iframe\n height370\n style{{ width: \100%\ }}\n scrollingno\n titleCodePen Embed\n src{embedUrl}\n frameBorderno\n allowTransparency\n allowFullScreen\n />\n );\n};\n// .../code>/pre>\n\n\n\np>Save the changes and voilá; we\re pretty much done with the custom CodePen block!/p>\n\n\n\nh2>Taking it further/h2>\n\n\n\np>Now, you probably noticed that Chris had put more settings into his custom block. Nothing is stopping us from doing the same! If we look up the documentation for the a hrefhttps://www.npmjs.com/package/react-codepen-embed>React CodePen embed component/a> that we installed, we\ll find a table of properties that it can take. We can add these as fields in the schema definition. For example, if we wanted to add the code>themeId/code>, we could do it as follows:/p>\n\n\n\npre relJSX classlanguage-jsx data-line classwp-block-csstricks-code-block>code markuptt>import React from react;\nimport Codepen from react-codepen-embed;\n\nconst CodePenPreview ({ value }) > {\n const { url, themeId dark } value; // < add themeId here, default it to dark\n const splitURL url.split(/);\n // \https:\, \\, \codepen.io\, \sdras\, \pen\, \gWWQgb\ \n const , , , user, , hash splitURL;\n const embedUrl `https://codepen.io/${user}/embed/${hash}?height370&theme-id${themeId}&default-tabresult`; // < add themeId here\n return (\n <iframe\n height370\n style{{ width: \100%\ }}\n scrollingno\n titleCodePen Embed\n src{embedUrl}\n frameBorderno\n allowTransparency\n allowFullScreen\n />\n );\n};\n\nexport default {\n name: codepen,\n type: object,\n title: CodePen Embed,\n preview: {\n select: {\n url: url,\n themeId: themeId // < add themeId here\n },\n component: CodePenPreview\n },\n fields: \n {\n name: url,\n type: url,\n title: CodePen URL\n },\n // Add the new field below\n {\n name: themeId,\n type: string,\n title: Theme ID,\n description: \You can use light and dark also.\\n }\n \n};/code>/pre>\n\n\n\nh2>Conclusion/h2>\n\n\n\np>We just looked at how schemas for Sanity Studio work, and learned how to make previews for custom components to boot! Hopefully, you now know enough to make pretty much em>any/em> custom component with a preview using these same principles. If you do, I would love to know about it either on a hrefhttps://twitter.com/kmelve>Twitter/a> or in the comments./p>\n,protected:e}},{id:304061,slug:pages-for-likes,title:{rendered:Pages for Likes},excerpt:{rendered:p>I posted about parsing an RSS feed in JavaScript the other day. I also posted about my RSS setup talking about how Feedbin is at the heart of it. Dave discovered that Feedbin can also produce an RSS feed for all your likes. Likes is a feature of Feedbin, and fortunately also NetNewsWire, which syncs …/p>\n,protected:e},date:2020-02-24T13:26:25,tags:1280,content:{rendered:\np>I posted about a hrefhttps://css-tricks.com/how-to-fetch-and-parse-rss-feeds-in-javascript/>parsing an RSS feed in JavaScript/a> the other day. I also posted about a hrefhttps://css-tricks.com/netnewswire-and-feedbin/>my RSS setup/a> talking about how a hrefhttps://feedbin.com/>Feedbin/a> is at the heart of it. /p>\n\n\n\np>Dave discovered that Feedbin can also em>produce/em> an RSS feed for all your likes. Likes is a feature of Feedbin, and fortunately also a hrefhttps://ranchero.com/netnewswire/>NetNewsWire/a>, which syncs the likes back to Feedbin. You have to flip a settings switch in Feedbin, but then you get a URL for your likes. a hrefhttps://feedbin.com/starred/56d6b0fe68e5efd3d447fd5bf328a57e.xml>Here\s mine./a> /p>\n\n\n\np>Unfortunately, the feed isn\t CORS ready, so you\ll have to run it through a proxy — but it\s doable. /p>\n\n\n\n\x3c!--more--\x3e\n\n\n\nul>li>Dave has a hrefhttps://daverupert.com/likes/>a likes page/a>/li>li>Robin has a hrefhttps://www.robinrendle.com/likes/>a likes page/a>/li>/ul>\n\n\n\np>Those are both JavaScript-powered. Here\s how they work:/p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_OJVRqav src//codepen.io/anon/embed/OJVRqav?height550&theme-id1&slug-hashOJVRqav&default-tabjs,result height550 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed OJVRqav titleCodePen Embed OJVRqav classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>I haven\t decided if I\m going to toss one up somewhere. If I do I\ll probably do it with a hrefhttps://css-tricks.com/the-deal-with-wordpress-transients/>WordPress Transients/a> as I\ve had some experience with that (that\s how a hrefhttps://css-tricks.com/jobs/>the jobs page/a> works, for example)./p>\n\n\n\nhr classwp-block-separator/>\n\n\n\np>Also, did you know you could a hrefhttps://www.bennadel.com/blog/3770-using-xslt-and-xml-transformations-to-style-my-blog-s-rss-feed-as-an-html-page.htm>style an RSS feed?/a> /p>\n,protected:e}},{id:302758,slug:gutenberging,title:{rendered:Gutenberging},excerpt:{rendered:p>It’s been over a year since the big WordPress launch of Gutenberg, the new editor. It seems to me most of the controversy around it has died down. There has been enough time that the UX and accessibility of it have improved, and people are seeing the potential a lot more clearly. There ain’t no …/p>\n,protected:e},date:2020-02-24T07:41:16,tags:1390,264,content:{rendered:\np>It\s been over a year since the big WordPress launch of a hrefhttps://wordpress.org/gutenberg/>Gutenberg/a>, the new editor. It seems to me most of the controversy around it has died down. There has been enough time that the UX and accessibility of it have improved, and people are seeing the potential a lot more clearly. There ain\t no turning back./p>\n\n\n\np>I\m running across articles like Haris Zulfiqar saying he\s a hrefhttps://hariszulfiqar.com/why-am-i-betting-on-gutenberg/>betting on it/a> and Nick Hamze saying that blocks are a hrefhttps://block.garden/for-the-future/>for the next generation/a>. /p>\n\n\n\np>While I think there are still rough edges (like why can\t I put a list in a blockquote? Why can\t I add a class to a link? Why can\t I arrow-key through the block chooser?), I\m a big fan overall. And not just conceptually anymore. a hrefhttps://css-tricks.com/thank-you-2019-edition/#article-header-id-8>I made it one of my 2020 goals/a> to get CSS-Tricks onto Gutenberg, and so I hopped to that right away in January./p>\n\n\n\n\x3c!--more--\x3e\n\n\n\nh3>We already had one foot in the door/h3>\n\n\n\np>We had a smidge of experience Gutenberging since we had already a hrefhttps://css-tricks.com/a-gutenburg-powered-newsletter/>converted the newsletter authoring experience/a> over to the new editor. Our newsletters are a Custom Post Type here on CSS-Tricks, which are published here at public URLs, have a custom RSS feed, and sent out by MailChimp which fetches and reads that RSS feed./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755219//newsletter.png?ssl1 alt classwp-image-302772 srcsethttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755219//newsletter.png?ssl1 2676w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_2048/v1582755219//newsletter.png 2048w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1744/v1582755219//newsletter.png 1744w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1406/v1582755219//newsletter.png 1406w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_901/v1582755219//newsletter.png 901w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755219//newsletter.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>We were able to just turn on Gutenberg for newsletters by way of the a hrefhttps://github.com/Automattic/gutenberg-ramp>Gutenberg Ramp/a> plugin. That works great for Custom Post Types and posts with individual IDs, but I wanted to turn on Gutenberg em>only for new content/em>. I wound up monkey-patching the plugin. a hrefhttps://github.com/Automattic/gutenberg-ramp/pull/82/files>Here\s a pull request/a> in case anyone over there thinks it\s a good idea. /p>\n\n\n\np>This was important to me, as we have tens of thousands of old posts created with the old editor, and even though Gutenberg doesn\t mangle them if we open them up for editing, the editor experience it provides for them isn\t as good as the classic editor (e.g. we have special buttons for our special code blocks and stuff like that). /p>\n\n\n\nh3>Dealing with older content/h3>\n\n\n\np>What would really be great is if Gutenberg would convert old posts into proper blocks upon opening, but that feels like a dream at this point. Like, it would have to parse the HTML, identify what chunks look like blocks, identify em>which/em> block makes the most sense, including our em>custom/em> blocks which are the most important, and be em>really correct/em> about it in a non-fragile way. /p>\n\n\n\np>For now, old content just uses the old editor. There isn\t even an easy way to flip on Gutenberg for an individual post from the editor. (I could hard-code values into the Gutenberg Ramp usage, but that\s a bit tedious.)/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755229//old-editor.png?ssl1 alt classwp-image-302797 srcsethttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755229//old-editor.png?ssl1 2220w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_2048/v1582755229//old-editor.png 2048w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1726/v1582755229//old-editor.png 1726w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1402/v1582755229//old-editor.png 1402w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_974/v1582755229//old-editor.png 974w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755229//old-editor.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>I worry a smidge that the old editor will really deteriorate. For example, one of the big reasons I got started with this is because, on this site, the old editor would just randomly scroll to the bottom of the page. I can\t for the life of me figure out why, but it makes authoring obnoxious for me. Just a little papercut bug that made me want to get on the editor experience that is being actively developed./p>\n\n\n\np>But even if the old editor really gets bad, just flipping on Gutenberg for everything isn\t that bad. All the old content will just be in a big classic block and will be fine./p>\n\n\n\nh3>So anyway — it\s working! /h3>\n\n\n\np>Turning on Gutenberg for new posts was its own little challenge, but it\s turned on for us and we\re creating all new content in it. I\m just speaking for myself here but strong>OMG I love it so much./strong> It\s such a massive upgrade for writing content that I\m a little obsessed with it. The team is happy as well./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755241//turned-on.png?ssl1 alt classwp-image-302780 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1922/v1582755241//turned-on.png 1922w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1523/v1582755241//turned-on.png 1523w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1225/v1582755241//turned-on.png 1225w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_775/v1582755241//turned-on.png 775w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755241//turned-on.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\nh3>Creating custom blocks/h3>\n\n\n\np>Check out this fancy text block we have:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755251//Screen-Shot-2020-01-27-at-1.06.56-PM.png?ssl1 alt classwp-image-302781 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1662/v1582755251//Screen-Shot-2020-01-27-at-1.06.56-PM.png 1662w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_884/v1582755251//Screen-Shot-2020-01-27-at-1.06.56-PM.png 884w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_685/v1582755251//Screen-Shot-2020-01-27-at-1.06.56-PM.png 685w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_428/v1582755251//Screen-Shot-2020-01-27-at-1.06.56-PM.png 428w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755251//Screen-Shot-2020-01-27-at-1.06.56-PM.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>A callout block on CSS-Tricks/figcaption>/figure>\n\n\n\np>You might think, oh cool, an opportunity for a custom block. Heck, we even covered learning and a hrefhttps://css-tricks.com/guides/learning-gutenberg/>making Gutenberg blocks in a whole big series/a>. But this brings up a pretty relevant situation: strong>when em>not/em> to build a block/strong>. The only thing unique about em>this/em> block is that is has a special class name that our CSS uses to style that block. That\s it. Adding a class name is strong>a built-in feature/strong> of every block, so a custom block here really isn\t necessary. /p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755257//add-class-to-block.png?ssl1 alt classwp-image-302788 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1892/v1582755257//add-class-to-block.png 1892w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755257//add-class-to-block.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>In fact, we can go a step further, and make a text block with this exact class a strong>reusable block/strong> so we don\t even have to remember or type in that class name. After I\ve created a text block with this class, I select Convert to Reusable Block from the kebab menu and now it\s forever saved as a reusable block./p>\n\n\n\ndiv classwp-block-image>figure classaligncenter size-large is-resized>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755262//reusable-blocks.png?resize364%2C230&ssl1 alt classwp-image-302790 width364 height230 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_874/v1582755262//reusable-blocks.png 874w, https://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755262//reusable-blocks.png?resize364%2C230&ssl1 364w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755262//reusable-blocks.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>/div>\n\n\n\np>We\re already using it for a few other things now, like our Article Series block (an code><h4>/code> and code><ol>/code> with a special code><div>/code>-with-a-class wrapper) and footnote blocks and such./p>\n\n\n\np>But we do actually need some custom blocks as well, and for that I used a hrefhttps://github.com/ahmadawais/create-guten-block>create-guten-block/a> to craft a special plugina href#fn:1>¹/a> to create them. I see One that is mega important for us is code blocks. There is already a native block for code blocks. It essentially puts the code in a code><pre>/code> tag and the content from Gutenberg is already escaped by default./p>\n\n\n\np>Our fancy code block allows us to pick which language it is, highlight certain lines, and provide custom labels. This was all possible in our old editor via HTML attributes, so this block is just nice UI on top of all that. /p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755264//code-block.png?ssl1 alt classwp-image-302791 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1890/v1582755264//code-block.png 1890w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1437/v1582755264//code-block.png 1437w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755264//code-block.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>That block is so specific to CSS-Tricks it doesn\t make much sense to open source it. But there is another block I created that is open source, and that\s the a hrefhttps://wordpress.org/plugins/codepen-embed-block/>CodePen Embed Block/a>. I a hrefhttps://blog.codepen.io/2020/01/22/a-gutenberg-block-for-codepen-embeds-on-wordpress/>wrote about it/a> over on the CodePen blog. /p>\n\n\n\np>It allows you to paste in a CodePen URL and it transforms into a CodePen Embed. oEmbed already does that by default, but with this plugin, you can control everything like the height, theme, and default tabs./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755269//embed-admin.png?ssl1 alt classwp-image-302792 srcsethttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755269//embed-admin.png?ssl1 2180w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_2048/v1582755269//embed-admin.png 2048w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1623/v1582755269//embed-admin.png 1623w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_1284/v1582755269//embed-admin.png 1284w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_786/v1582755269//embed-admin.png 786w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755269//embed-admin.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>It\s pretty awesome to actually see the embedded Pens while authoring!/p>\n\n\n\nh3>Unfaced challenges/h3>\n\n\n\np>The biggest challenge right now is handling images. In the old editor, we have integrated a hrefhttps://css-tricks.com/video-screencasts/155-responsive-images-wordpress-cloudinary/>a very very fancy setup/a> with a hrefhttps://cloudinary.com/>Cloudinary/a>. The images are automatically uploaded to Cloudinary, breakpoints are programmatically decided on, multiple sizes are created, a responsive images syntax is created, and what ends up in the HTML is a perfect responsive images syntax with the images hosted by Cloudinary. This has the provided us with the benefit of being on a CDN and serving the images in the best possible format as well./p>\n\n\n\np>None of that is happening on posts created with Gutenberg. 😭/p>\n\n\n\np>I need to find or develop a new system that does a great job with images everywhere on the site and ideally with a less bespoke system that is easier to maintain. It\s possible I figure that out with Cloudinary, I might try some other service, I might let WordPress deal with it directly backed by the a hrefhttps://jetpack.com/support/site-accelerator/>Jetpack Site Accelerator/a>. Not sure yet. Always something to do. /p>\n\n\n\ndiv classwp-block-group footnotes idfn:1>div classwp-block-group__inner-container>\nol>li>I see WordPress themselves is getting in on the block scaffolding game. Their create-wordpress-block concept has made its way into a hrefhttps://github.com/wordpress/gutenberg/>the Gutenberg repo/a> itself, which you kick off with code>npm init @wordpress/block options slug/code>/li>/ol>\n/div>/div>\n,protected:e}},{id:302869,slug:wpaudit-site,title:{rendered:wpaudit.site},excerpt:{rendered:p>A big checklist of things you could/should be doing to make your website the best it can be. 80% of which is a good idea for any website, not just a WordPress website. I’m linking to it because I like how plain language it is, and because it’s a good example of how giving something …/p>\n,protected:e},date:2020-02-24T07:41:06,tags:,content:{rendered:\np>A big checklist of things you could/should be doing to make your website the best it can be. 80% of which is a good idea for any website, not just a WordPress website. /p>\n\n\n\np>Im linking to it because I like how plain language it is, and because its a good example of how giving something away helps more than it hurts. This is essentially a marketing site for Aurooba Ahmeds auditing services. Its not a mystery what Aurooba is going to help you with if you hire her for an audit because she tells you exactly what she is going to do. This public checklist doesnt make me go, \Oh, Ill do it myself then.\ It makes me go, \Nice, she clearly knows what shes doing, lets let her do it.\/p>\n,protected:e}},{id:303595,slug:fixed-headers-and-jump-links-the-solution-is-scroll-margin-top,title:{rendered:Fixed Headers and Jump Links? The Solution is scroll-margin-top},excerpt:{rendered:p>The problem: you click a jump link like <a href”#header-3″>Jump</a> which links to something like <h3 id”header-3″>Header</h3>. That’s totally fine, until you have a position: fixed; header at the top of the page obscuring the header you’re trying to link to! Fixed headers have a nasty habit of hiding the element you’re trying to link …/p>\n,protected:e},date:2020-02-21T14:48:49,tags:1113,1331,11750,1640,content:{rendered:\np>The problem: you click a jump link like code><a href#header-3>Jump</a>/code> which links to something like code><h3 idheader-3>Header</h3>/code>. That\s totally fine, until you have a code>position: fixed;/code> header at the top of the page obscuring the header you\re trying to link to!/p>\n\n\n\np>Fixed headers have a nasty habit of hiding the element you\re trying to link to. /p>\n\n\n\n\x3c!--more--\x3e\n\n\n\nfigure classwp-block-image size-large is-resized>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754908//hidden-header.png?resize482%2C177&ssl1 alt classwp-image-303597 width482 height177 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_651/v1582754908//hidden-header.png 651w, https://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582754908//hidden-header.png?resize482%2C177&ssl1 482w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582754908//hidden-header.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />/figure>\n\n\n\np>There used to be a hrefhttps://css-tricks.com/hash-tag-links-padding/>all kinds of wild hacks/a> to get around this problem. In fact, in the design of CSS-Tricks as I write, I was like, em>Screw it, I\ll just have a big generous code>padding-top/code> on my in-article headers because I don\t mind that look anyway. /em>/p>\n\n\n\np>But there is actually a really straightforward way of handling this in CSS now. /p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>h3 {\n scroll-margin-top: 5rem; /* whatever is a nice number that gets you past the header */\n}/code>/pre>\n\n\n\np>a hrefhttp://css-tricks.com/almanac/properties/s/scroll-margin/>We have an Almanac article on it/a>, which includes browser support, which is essentially everywhere. It\s often talked about in conjunction with a hrefhttps://css-tricks.com/practical-css-scroll-snapping/>scroll snapping/a>, but I find this use case even more practical. /p>\n\n\n\np>Here\s a simple demo:/p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_GRJpopp src//codepen.io/anon/embed/GRJpopp?height450&theme-id1&slug-hashGRJpopp&default-tabresult height450 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed GRJpopp titleCodePen Embed GRJpopp classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>In a related vein, that weird (but cool) text fragments link that Chrome shipped takes you to a hrefhttps://twitter.com/chriscoyier/status/1225199469446090752>the middle of the page/a> instead, which I think is nice./p>\n,protected:e}},{id:304009,slug:inspiring-high-school-students-with-html-and-css,title:{rendered:Inspiring high school students with HTML and CSS},excerpt:{rendered:p>Here’s a heartwarming post from Stephanie Stimac on her experience teaching kids the very basics of web development: … the response from that class of high school students delighted me and grounded me in a way I haven’t experienced before. What I view as a simple code was absolute magic to them. And for all …/p>\n,protected:e},date:2020-02-21T14:48:42,tags:870,content:{rendered:\np>Here’s a heartwarming post from Stephanie Stimac on her experience teaching kids the very basics of web development:/p>\n\n\n\nblockquote classwp-block-quote>p>... the response from that class of high school students delighted me and grounded me in a way I haven\t experienced before. What I view as a simple code was absolute magic to them. And for all of us who code, I think we forget it is magic. Computational magic but still magic. HTML and CSS em>are/em> magic./p>/blockquote>\n\n\n\n\x3c!--more--\x3e\n\n\n\np>Publishing anything on the web is always going to be magic to some degree but sometimes it’s easy to forget on a day to day basis. We have to brush off the cobwebs! Shake our tailfeathers! And remind ourselves and everyone around us that the basics of web development are precious and fun and exciting still. Especially so we can help inspire the next generation of web designers and developers./p>\n,protected:e}},{id:303988,slug:ios-13-design-guidelines-templates-and-downloads,title:{rendered:iOS 13 Design Guidelines, Templates, and Downloads},excerpt:{rendered:p>Erik Kennedy wrote up a bunch of design advice for designing for the iPhone. Like Apple’s Human Interface Guidelines, only illustrated and readable, says Erik. This is mostly for native iOS apps kinda stuff, but it makes me wonder how much of this is expected when doing a mobile Progressive Web App. On one hand, …/p>\n,protected:e},date:2020-02-21T07:46:19,tags:692,872,content:{rendered:\np>Erik Kennedy wrote up a hrefhttps://app.learnui.design/a/aff_systqg5d/external?affcode70335_li1b9fix>a bunch of design advice/a> for designing for the iPhone. q>Like Apple\s a hrefhttps://developer.apple.com/design/human-interface-guidelines/>Human Interface Guidelines/a>, only illustrated and readable/q>, says Erik. /p>\n\n\n\np>This is mostly for native iOS apps kinda stuff, but it makes me wonder how much of this is expected when doing a mobile Progressive Web App. On one hand, this kind of stuff looks fun to try to build on the web, and it would be kinda cool to make your web app feel super native. On the other hand, doesn\t that make it extra awkward for Android and other non-iOS platforms? /p>\n\n\n\n\x3c!--more--\x3e\n\n\n\np>A few other thoughts:/p>\n\n\n\nul>li>How much of this stuff do you get for free with a hrefhttps://developer.apple.com/xcode/swiftui/>SwiftUI/a>? /li>li>As I understand it, when you build apps with a hrefhttps://flutter.dev/docs/development/ui/widgets/material>Flutter / Material/a>, the native apps that get built do some smart cross-platform stuff, mimicking how that platform does things. /li>/ul>\n\n\n\np>Erik also does very in-depth design training with enrollment only opening once in a while, a hrefhttps://app.learnui.design/a/aff_cl3dgcl4/external?affcode70335_li1b9fix>the next opens March 4th./a>/p>\n,protected:e}},{id:303261,slug:animate-svg-path-changes-in-css,title:{rendered:Animate SVG Path Changes in CSS},excerpt:{rendered:p>Every once in a while I’m motivated to attempt to draw some shapes with <path>, the all-powerful drawing syntax of SVG. I only understand a fragment of what it all can do, but I know enough to be dangerous. All the straight-line syntax commands (like L) are pretty straightforward and I find the curved Q …/p>\n,protected:e},date:2020-02-20T14:49:25,tags:,content:{rendered:\np>Every once in a while I\m motivated to attempt to draw some shapes with code><path>/code>, the a hrefhttps://css-tricks.com/svg-path-syntax-illustrated-guide/>all-powerful drawing syntax/a> of SVG. I only understand a fragment of what it all can do, but I know enough to be dangerous. All the straight-line syntax commands (like code>L/code>) are pretty straightforward and I find the curved code>Q/code> command fairly intuitive. Box yourself into a code>viewBox0 0 100 100/code> and drawing simple stuff doesn\t seem so bad./p>\n\n\n\n\x3c!--more--\x3e\n\n\n\np> Here\s a classic example of mine that draws things with all the basic commands, em>but also animates them with CSS/em> (Chromium browsers only): /p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_NRwANp src//codepen.io/anon/embed/NRwANp?height550&theme-id1&slug-hashNRwANp&default-tabresult height550 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed NRwANp titleCodePen Embed NRwANp classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>Weird but true:/p>\n\n\n\npre relHTML classwp-block-csstricks-code-block language-markup data-line>code markuptt><svg viewBox0 0 10 10>\n <path dM2,2 L8,8 />\n</svg>/code>/pre>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>svg:hover path {\n transition: 0.2s;\n d: path(M8,2 L2,8);\n}/code>/pre>\n\n\n\np>The other day I had a situation where I needed a UI element that has a different icon depending on what state it\s in. It was kind of a log shape so the default was straight lines, kinda like a hamburger menu (only four lines so it read more like lines of text), then other various states./p>\n\n\n\nol>li>DEFAULT/li>li>ACTIVE/li>li>SUCCESS/li>li>ERROR/li>/ol>\n\n\n\np>First I wrote the most complicated state machine in the world:/p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>const indicator document.querySelector(.element);\n\nlet currentState indicator.dataset.state;\n\nindicator.addEventListener(click, () > {\n let nextState ;\n\n if (currentState DEFAULT) {\n nextState ACTIVE;\n } else if (currentState ACTIVE) {\n nextState SUCCESS;\n } else if (currentState SUCCESS) {\n nextState ERROR;\n } else {\n nextState DEFAULT;\n }\n \n indicator.dataset.state nextState;\n currentState nextState;\n});/code>/pre>\n\n\n\np>That opened the door for styling states with data-attributes:/p>\n\n\n\npre relSCSS classwp-block-csstricks-code-block language-scss data-line>code markuptt>.element {\n \n &data-stateDEFAULT {\n }\n &data-stateACTIVE {\n }\n &data-stateSUCCESS {\n }\n &data-stateERROR {\n }\n\n}/code>/pre>\n\n\n\np>So now if my element starts with the default state of four lines:/p>\n\n\n\npre relHTML classwp-block-csstricks-code-block language-markup data-line>code markuptt><div classelement data-stateDEFAULT>\n <svg viewBox0 0 100 100 classicon>\n <path dM0, 20 Q50, 20 100, 20></path>\n <path dM0, 40 Q50, 40 100, 40></path>\n <path dM0, 60 Q50, 60 100, 60></path>\n <path dM0, 80 Q50, 80 100, 80></path>\n </svg>\n</div>\n/code>/pre>\n\n\n\np>...I can alter those paths in CSS for the rest of the states. For example, I can take those four straight lines and alter them in CSS./p>\n\n\n\np classexplanation>Note the four straight lines conveniently have an unused curve point in them. Only paths that have the same number and type of points in them can be animated in CSS. Putting the curve point in there opens doors./p>\n\n\n\np>These four new paths actually draw something close to a circle! /p>\n\n\n\npre relSCSS classwp-block-csstricks-code-block language-scss data-line>code markuptt>.editor-indicator {\n \n &data-stateACTIVE {\n .icon {\n :nth-child(1) {\n d: path(M50, 0 Q95, 5 100,50);\n }\n :nth-child(2) {\n d: path(M100, 50 Q95, 95 50,100);\n }\n :nth-child(3) {\n d: path(M50,100 Q5, 95 0, 50);\n }\n :nth-child(4) {\n d: path(M0, 50 Q5, 5 50, 0);\n }\n }\n }\n\n}/code>/pre>\n\n\n\np>For the other states, I drew a crude checkmark (for SUCCESS) and a crude exclamation point (for FAILURE). /p>\n\n\n\np>Here\s a demo (again, Chromium), where you can click it to change the states:/p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_wvBZyXX src//codepen.io/anon/embed/wvBZyXX?height250&theme-id1&slug-hashwvBZyXX&default-tabresult height250 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed wvBZyXX titleCodePen Embed wvBZyXX classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>I didn\t end up using the thing because neither Firefox nor Safari support the code>d: path();/code> thing in CSS. Not that it doesn\t animate them, it just doesn\t work period, so it was out for me. I just ended up swapping out the icons in the different states. /p>\n\n\n\np>If you need cross-browser shape morphing, we have a hrefhttps://css-tricks.com/many-tools-shape-morphing/>a whole article about that/a>. /p>\n,protected:e}},{id:303621,slug:a-guide-to-console-commands,title:{rendered:A Guide to Console Commands},excerpt:{rendered:p>The developer’s debugging console has been available in one form or another in web browsers for many years. Starting out as a means for errors to be reported to the developer, its capabilities have increased in many ways; such as automatically logging information like network requests, network responses, security errors or warnings. There is also …/p>\n,protected:e},date:2020-02-20T07:48:28,tags:11782,1479,content:{rendered:\np>The developer’s debugging console has been available in one form or another in web browsers for many years. Starting out as a means for errors to be reported to the developer, its capabilities have increased in many ways; such as automatically logging information like network requests, network responses, security errors or warnings./p>\n\n\n\np>There is also a way for a website’s JavaScript to trigger various commands that output to the console for debugging purposes. These commands are contained in a console object available in almost every browser. Even though these features are mostly consistent between browsers, there are a few differences. Some of these differences are simply visual in nature while others do have slight functional differences to keep in mind./p>\n\n\n\n\x3c!--more--\x3e\n\n\n\np>For the curious, here’s the a hrefhttps://console.spec.whatwg.org/>spec/a> by a hrefhttps://whatwg.org/>WHATWG /a>linked from the a hrefhttps://developer.mozilla.org/en-US/docs/Web/API/console>MDN console docs/a>./p>\n\n\n\np>This guide covers what’s available in the console object of Firefox and Chrome as they are often the most popular browsers for development and they do have a few differences in various aspects of the console. The new a hrefhttps://www.microsoft.com/en-us/edge>Chromium-based Edge/a> is essentially the same as Chrome in many ways so, in most cases, the console commands will operate much the same./p>\n\n\n\ndetails stylebackground:#fff6ea;padding:.75em;>\nsummary stylefont-size:1.5em;>Quick Links/summary>\n\n\n\nul>li>a href#article-header-id-0>Logging/a>/li>li>a href#article-header-id-1>Clearing/a>/li>li>a href#article-header-id-2>Common Commands/a>/li>li>a href#article-header-id-3>String substitution/a>/li>li>a href#article-header-id-4>Styling the output/a>/li>li>a href#article-header-id-5>Assertions/a>/li>li>a href#article-header-id-6>Counting Commands/a>/li>li>a href#article-header-id-7>Listing Properties/a>/li>li>a href#article-header-id-8>Group Commands/a>/li>li>a href#article-header-id-9>Table Command/a>/li>li>a href#article-header-id-10>Time Commands/a>/li>li>a href#article-header-id-11>Showing Traces/a>/li>li>a href#article-header-id-12>Debugger Command/a>/li>li>a href#article-header-id-13>Console Utilities/a>/li>/ul>\n\n\n\n/details>\n\n\n\nhr classwp-block-separator/>\n\n\n\nh3>The console.log command/h3>\n\n\n\np>The first thing we can do is log the console object itself to see what your browser of choice actually offers./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.log(console);/code>/pre>\n\n\n\np>This command will output the various properties of the console object as the browser knows them. Most of them are functions and will be rather consistent regardless of browser. If there are differences in the properties of the console object from one browser to another, this way you can see the differences. One such difference I can point out between Firefox and Chrome is that Chrome provides a “memory” property that outputs some basic memory usage stats. Firefox doesn’t provide this property and yet has a “name” property that Chrome does not have./p>\n\n\n\np>Thankfully, most of the differences between the browsers tend to be just as trivial. That way, you can be fairly confident that your code will output much the same regardless of the browser in use./p>\n\n\n\nh3>First things first: clear()/h3>\n\n\n\np>With heavy usage of the console comes a very crowded output of text. Sometimes you just want to clear things out and start with a fresh console. Browsers typically provide a button in DevTools that performs this task. However, the console object itself also provides a command to handle this:/p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.clear();/code>/pre>\n\n\n\np>This will clear the console and will helpfully inform you of that by outputting a message like Console was cleared./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/css-tricks.com/wp-content/uploads/2020/02/image_preview.gif?ssl1 alt classwp-image-303627 data-recalc-dims1/>/figure>\n\n\n\nh3>Common usage: debug(), error(), info(), log(), and warn()/h3>\n\n\n\np>There are five commands that at first glance seem to do the exact same thing. And, technically, they do. But browsers provide additional features tied to the five commands to give each their own distinct benefit./p>\n\n\n\np>These five commands are:/p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.debug();\nconsole.error();\nconsole.info();\nconsole.log();\nconsole.warn();/code>/pre>\n\n\n\np>I’m sure many of you have seen code>console.log()/code> before (I mean, we em>just/em> talked about it up top) and have probably used it before. Before we get into what you can log in these five commands, let’s see our first minor difference between Chrome and Firefox./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755150//image_preview-1.png?ssl1 alt classwp-image-303628 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_744/v1582755150//image_preview-1.png 744w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755150//image_preview-1.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome console showing debug, error, info, log, and warn/figcaption>/figure>\n\n\n\np>This is an example in Chrome of each command outputting a string, such as code>console.debug(\console.debug()\);/code>. Notice that some of them have a color treatment to give a visual indication of the type of output it is. The error and warn outputs have an additional icon for even easier identification./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755152//image_preview-2.png?ssl1 alt classwp-image-303632 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_753/v1582755152//image_preview-2.png 753w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755152//image_preview-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Firefox console showing debug, error, info, log, and warn/figcaption>/figure>\n\n\n\np>Here is the same list in Firefox and, while it looks similar, there are three minor differences. For example, code>console.debug()/code> is not color-coded and code>console.info()/code> has an additional icon next to it. In Chrome, both code>console.error()/code> and code>console.warn()/code> can be expanded to show additional information about the output while Firefox only does this with code>console.error()/code>. This additional information provides a trace of the lines of code involved to get to where the particular command was called./p>\n\n\n\np>One thing that is useful about these five commands is that the browsers provide filtering options to show or hide each type as you wish. Firefox has them right there at the top of the console above the output while Chrome hides them in a dropdown, labeled “All levels” which you can see in the earlier Chrome console screenshot. “All levels” is there because I have all five set to be shown. If you were to choose the “Default” option then the debug output (listed as Verbose) is hidden while the others are shown. Unchecking Info, Warnings, or Errors causes the dropdown to display a different title such as Custom levels or Errors only depending on what is selected./p>\n\n\n\np>The intentions for usage of error and warn are easy to determine; how to use the other choices is up to you. If you do make extensive use of the different options then you might consider documenting the expectations of each as to not confuse things late in the project — especially if it is a team project./p>\n\n\n\np>Now, let’s discuss what we can actually log inside these commands. Since they all behave the same, I’ll just focus on logging as the example./p>\n\n\n\np>The simplest examples involve just passing a string, number, object, or array into the log command. Technically, any of JavaScript’s data types can be used, but for most of them, the output is much the same./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.log(\string\);\nconsole.log(42);\nconsole.log({object: \object\});\nconsole.log(\array\, \array\);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755153//image_preview-3.png?ssl1 alt classwp-image-303633 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_745/v1582755153//image_preview-3.png 745w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755153//image_preview-3.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome string, number, object, and array log examples/figcaption>/figure>\n\n\n\np>I’m showing these examples in Chrome with the object and array already expanded. They are normally collapsed but the output next to the arrow is consistent between both states. Firefox displays a little differently but, for the most part, the output is the same. Firefox does tell you whether it is displaying an object or array before expanding, but shows the same as Chrome while expanded./p>\n\n\n\np>One interesting thing to add is that you can pass more than one item to the log as parameters and it’ll display them inline./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.log(\string\, \string\);\nconsole.log(42, 1138);\nconsole.log({object: \object\}, {object: \object\});\nconsole.log(\array\, \array\, \array\, \array\);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755155//image_preview-4.png?ssl1 alt classwp-image-303634 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_744/v1582755155//image_preview-4.png 744w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755155//image_preview-4.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome strings, numbers, objects, and arrays examples/figcaption>/figure>\n\n\n\np>Often when I’m working with x and y coordinates, such as what can be outputted by mouse events, it’s useful to log the two together in one statement./p>\n\n\n\nh3>String substitution/h3>\n\n\n\np>The different console logging commands provide string substitution that allows inserting different values into the string for output. This is useful for describing a variable in the log to make it clear as to what’s being reported./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.log(\This is a string: %s\, \string\);\nconsole.log(\This is a number: %i\, 42);\nconsole.log(\This is an object: %o\, {object: \object\});/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755157//image_preview-5.png?ssl1 alt classwp-image-303635 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_744/v1582755157//image_preview-5.png 744w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755157//image_preview-5.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome string substitution examples/figcaption>/figure>\n\n\n\np>Here is a list of the data types that can substituted into the output string:/p>\n\n\n\nfigure classwp-block-table>table class>thead>tr>th>Data type/th>th>Substitution symbol/th>/tr>/thead>tbody>tr>td>\nObjects and arrays\n/td>td> code>%o/code> or code>%O/code> /td>/tr>tr>td>\nIntegers\n/td>td> code>%d/code> or code>%i/code>/td>/tr>tr>td>\nStrings\n/td>td> code>%s/code>/td>/tr>tr>td>\nFloats\n/td>td> code>%f/code>/td>/tr>/tbody>/table>/figure>\n\n\n\np>The first parameter would be the string to output with the symbols placed in the appropriate locations. Then each parameter after that is the value to substitute inside the first parameter’s string. Keep in mind that you’ll have to keep the substitution types and the parameters in the specific order or you’ll get unexpected results./p>\n\n\n\np>If your console supports a hrefhttps://css-tricks.com/template-literals/>template literals/a>, it’s a bit easier to get similar results as string substitutions./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.log(`This is a string: ${\string\}`);\nconsole.log(`This is a number: ${42}`);\nconsole.log(`This is an object: ${{object: \object\}}`);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755158//image_preview-2-1.png?ssl1 alt classwp-image-303636 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_743/v1582755158//image_preview-2-1.png 743w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755158//image_preview-2-1.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome template literal examples/figcaption>/figure>\n\n\n\np>Notice that the object is handled a bit better with the string substitution, so pick the appropriate choice for your requirements. Since it’s possible to insert more than one value in the output, let’s compare the two./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.log(\This is a string: %s. This is a number: %i\, \string\, 42);\nconsole.log(`This is a string: ${\string\}. This is a number: ${42}`);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755159//image_preview-3-1.png?ssl1 alt classwp-image-303637 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_744/v1582755159//image_preview-3-1.png 744w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755159//image_preview-3-1.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome string substitution and template literals/figcaption>/figure>\n\n\n\np>With the string substitution each value is added as a parameter to be inserted into the output. With template literals, on the other hand, you add them wherever they need to be in the output. Also, you can combine them./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.log(`This is a number: ${42}. This is an object: %o`, {object: \object\});/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755161//image_preview-4-1.png?ssl1 alt classwp-image-303638 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_745/v1582755161//image_preview-4-1.png 745w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755161//image_preview-4-1.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome string substitution with template literals/figcaption>/figure>\n\n\n\np>So, there are lots of options to pick and choose from so you can go with the best options for your needs. /p>\n\n\n\nh3>Styling the output/h3>\n\n\n\np>Another potentially useful and fun thing is that you can apply CSS styles to the console’s output. It works just like the string substitution method where you insert a code>%c/code> variable for styles to be applied from the parameters./p>\n\n\n\np>Here’s a simple example:/p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.log(\%cThis is large red text\, \color: red; font-size: 30px;\);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755162//image_preview-5-1.png?ssl1 alt classwp-image-303639 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_745/v1582755162//image_preview-5-1.png 745w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755162//image_preview-5-1.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome styling in the console/figcaption>/figure>\n\n\n\np>This time there is a slight difference in the Firefox output:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755163//image_preview-6.png?ssl1 alt classwp-image-303640 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_753/v1582755163//image_preview-6.png 753w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755163//image_preview-6.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Firefox styling in the console/figcaption>/figure>\n\n\n\np>Not really that much of a difference, but something to keep in mind./p>\n\n\n\np>What essentially happens is that code>%c/code> reads the strings in the parameters to determine what styling to apply. So, say there’s a second styling being passed, code>%c/code> moves on to the next parameter, much like with string substitution. An empty string in the parameter list resets the styling back to default./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.log(\This is %cred text %cand this is %cgreen text.\, \color: red;\, \\, \color: green;\);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755165//image_preview-2-2.png?ssl1 alt classwp-image-303641 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_744/v1582755165//image_preview-2-2.png 744w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755165//image_preview-2-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Using multiple styles in the Chrome console./figcaption>/figure>\n\n\n\np>The styling properties available are rather limited when compared to typical CSS styling on a webpage. You can look at it as a sort of inline block of text that allow you to manipulate a limited set of styling properties./p>\n\n\n\np>With some work and experimenting, you could create interesting messaging within the console. One idea is to draw extra attention to a particular log, especially an error of some sort./p>\n\n\n\npre relHTML classwp-block-csstricks-code-block language-markup data-line>code markuptt>console.log(\%cHello there!\, `\n background: white;\n border: 3px solid red;\n color: red;\n font-size: 50px;\n margin: 40px;\n padding: 20px;\n`);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755166//image_preview-3-2.png?ssl1 alt classwp-image-303642 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_752/v1582755166//image_preview-3-2.png 752w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755166//image_preview-3-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome custom styling/figcaption>/figure>\n\n\n\np>In this example, we can see that the CSS is a bit verbose, but there is something we can do to mimic the class system that we leverage in CSS. The values of each parameter for styling can be stored in variables to allow for repeated use without having to duplicate the string of styles in each parameter./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>const clearStyles \\;\nconst largeText \font-size: 20px;\;\nconst yellowText \color: yellow;\;\nconst largeRedText \font-size: 20px; color: red;\;\nconst largeGreenText \font-size: 20px; color: green;\;\n\u2028\nconsole.log(`This is %clarge red text.\n%cThis is %clarge green text.\n%cThis is %clarge yellow text.`,\n largeRedText,\n clearStyles,\n largeGreenText,\n clearStyles,\n largeText + yellowText\n);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755169//image_preview-4-2.png?ssl1 alt classwp-image-303643 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_751/v1582755169//image_preview-4-2.png 751w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755169//image_preview-4-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome custom template styling/figcaption>/figure>\n\n\n\np>There are several things going on here, so let’s break it down a bit. First, we have a collection of variables that holds our styling strings. Think of each as a sort of class to be reused in the parameters of the console log./p>\n\n\n\np>We are also using a template literal in the log, which means we can have line breaks in our output. Then, for each code>%c/code> in the text, there’s a corresponding variable used in a parameter to define the styles for that particular part of the output text. In addition to each variable that holds styling, there is also a code>clearStyles/code> argument that can be used to reset styles to prepare for the next set of styling. You could just use an empty string as in previous examples, but I like the clear intention that comes from using the variable name. The last parameter shows that the variables can be combined, which opens up more possible ways of handling the styles./p>\n\n\n\np>Now, that’s a great deal of text covering essentially five console commands that only output text to the console. So, let’s move on to other commands of the console object. Although, some of these can still use many of the features described so far, we won’t focus on that aspect as much with the following commands./p>\n\n\n\nh3>Being assertive: assert()/h3>\n\n\n\np>The code>console.assert()/code> command is similar to the error command mentioned previously. The difference is that asserting allows for the usage of a boolean condition to determine whether it should output the text to the console./p>\n\n\n\np>For example, let’s say you wanted to test the value of a variable and make sure it wasn’t larger than a certain number value. If the variable is below that number and the condition resolves to true, the assert command does nothing. If the condition resolves to false, then the output text is displayed. This way you don’t have to wrap a code>console.error()/code> command with an code>if/code> statement to determine if the error message is needed in the first place./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>let value 10;\nconsole.assert(value < 7, \The value is greater than 7.\);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755170//image_preview-5-2.png?ssl1 alt classwp-image-303644 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_752/v1582755170//image_preview-5-2.png 752w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755170//image_preview-5-2.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome assert example/figcaption>/figure>\n\n\n\np>We can see that assert has the same appearance as the error command, except that it also prepends “Assertion failed:” to the output text. Chrome can also expand this output to show a trace of where the assertion came from./p>\n\n\n\np>The trace can be quite helpful with common patterns of functions within functions calling other functions and so on. Although, you can see in the example above that the line the assert came from doesn’t tell you how the code got to that line./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>let value 10;\n\u2028\nfunction function_one () {\n function_two();\n}\n\u2028\nfunction function_two () {\n function_three();\n}\n\u2028\nfunction function_three() {\n console.assert(value < 7, \This was false.\);\n}\n\u2028\nfunction_one();/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755171//image_preview-7.png?ssl1 alt classwp-image-303645 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_751/v1582755171//image_preview-7.png 751w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755171//image_preview-7.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome assert with trace/figcaption>/figure>\n\n\n\np>This sequence is actually in reverse order in terms of the code. The last line shows an anonymous entry (which is an HTML script tag in this case) on line 78. That’s where code>function_one/code> was called. Inside that function, we have a call for code>function_two/code>, which, in turn, calls code>function_three/code>. Inside that last function is where the assert is located. So, in this development world of functions sharing other functions; a description of the path to that point of the assert is quite handy./p>\n\n\n\np>Unfortunately, this trace is not provided in Firefox with the assert command, as it is with the error command./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755173//image_preview-2-3.png?ssl1 alt classwp-image-303646 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_759/v1582755173//image_preview-2-3.png 759w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755173//image_preview-2-3.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Firefox assert example/figcaption>/figure>\n\n\n\nh3>Keeping count: count() and countReset()/h3>\n\n\n\np>Ever wonder how many times a certain thing happens in your code? For instance, how many times does a particular function get called during a sequence of events? That’s where the code>console.count()/code> command can help out./p>\n\n\n\np>By itself, the count command is rather simple and has limited use. If you use the command in its default state you only get a simple count. For example, if we call it three times in a row, we get a sequential count./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.count();\nconsole.count();\nconsole.count();/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755175//image_preview-3-3.png?ssl1 alt classwp-image-303647 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_751/v1582755175//image_preview-3-3.png 751w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755175//image_preview-3-3.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome default count example/figcaption>/figure>\n\n\n\np>As you can see, we get a simple count from one to three. The default behavior means that count is merely incrementing the output by one each time it runs, no matter where it shows up in the code. You do get the line number in the code where it happened, but the count is a simple total no matter the situation./p>\n\n\n\np>To make this command a bit more useful, we can provide a label to keep a separate count for that label./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.count(\label A\);\nconsole.count(\label B\);\nconsole.count(\label A\);\nconsole.count(\label B\);\nconsole.count(\label A\);\nconsole.count(\label B\);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755176//image_preview-4-3.png?ssl1 alt classwp-image-303648 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_753/v1582755176//image_preview-4-3.png 753w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755176//image_preview-4-3.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome label count example/figcaption>/figure>\n\n\n\np>Even though using the count command with labels causes the output to alternate between labels, each one keeps its own count. One scenario where this comes in handy is placing a count inside a function so that every time that function is called, the count is incremented. The label option makes it so that a count can be kept for individual functions to provide for a good idea of how many times each function is being called. That’s great for troubleshooting performance bottlenecks or simply seeing how much work a page is doing./p>\n\n\n\np>There’s a way to reset the count. Let’s say we have a loop that gets called multiple times, but the number of iterations of the loop can be dynamic. This is done with the code>console.countReset()/code> command with the same label from the count command./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.count();\nconsole.count();\nconsole.countReset();\nconsole.count();\n\u2028\nconsole.count(\this is a label\);\nconsole.count(\this is a label\);\nconsole.countReset(\this is a label\);\nconsole.count(\this is a label\);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755177//image_preview-5-3.png?ssl1 alt classwp-image-303649 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_752/v1582755177//image_preview-5-3.png 752w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755177//image_preview-5-3.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome count reset example/figcaption>/figure>\n\n\n\np>Each count — with and without a label — is called twice and code>console.countReset()/code> is applied right before another count instance. You can see that Chrome counts up to two, then restarts when it encounters countReset. There’s nothing in DevTools to indicate the reset happened, so an assumption is made that it did happen because the count started over./p>\n\n\n\np>And yet, the same code is a bit different in Firefox./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755179//image_preview-8.png?ssl1 alt classwp-image-303650 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_752/v1582755179//image_preview-8.png 752w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755179//image_preview-8.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Firefox count reset example/figcaption>/figure>\n\n\n\np>Here, the reset is indicated by the count being set all the way back to zero. That is the indicator that the reset was called, whereas we have no such indication in Chrome./p>\n\n\n\np>As for label options, just about anything can be used. I suppose a simple way to describe it is that if you give it anything that can be resolved to a string, it’ll probably work as a label. You could even use a variable that has values that change over time, where count will use the current value of the variable as a label each time it is encountered. So, you could keep count of the values as they change over time./p>\n\n\n\nh3>Describe that thing: dir() and dirxml()/h3>\n\n\n\np>The main idea behind these two commands is to display either properties of a Javascript object with code>console.dir()/code> or descendant elements of an XML/HTML element with code>console.dirxml()/code>. It appears Chrome has these implemented as expected, while Firefox just uses both as aliases for code>console.log()/code>./p>\n\n\n\np>Let’s give code>console.log()/code>, code>console.dir()/code>, and code>console.dirxml()/code> the same simple object to see what we get. Keep in mind that you normally would not log an object with code>console.dirxml()/code>./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>const count {\n one: \one\,\n two: \two\,\n three: \three\\n};\n\u2028\nconsole.log(count);\nconsole.dir(count);\nconsole.dirxml(count);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755181//image_preview-2-4.png?ssl1 alt classwp-image-303651 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_752/v1582755181//image_preview-2-4.png 752w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755181//image_preview-2-4.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome simple code>dir()/code> and code>dirxml()/code> example/figcaption>/figure>\n\n\n\np>Firefox gives us much the same, except the code>console.dir()/code> is automatically expanded./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755182//image_preview-3-4.png?ssl1 alt classwp-image-303652 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_753/v1582755182//image_preview-3-4.png 753w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755182//image_preview-3-4.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Firefox simple code>dir()/code> and code>dirxml()/code> example/figcaption>/figure>\n\n\n\np>Another simple comparison to code>console.log()/code> is to repeat the object in the same command./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755183//image_preview-4-4.png?ssl1 alt classwp-image-303653 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_751/v1582755183//image_preview-4-4.png 751w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755183//image_preview-4-4.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome code>dir()/code> and code>dirxml()/code> double example/figcaption>/figure>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755185//image_preview-5-4.png?ssl1 alt classwp-image-303654 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_753/v1582755185//image_preview-5-4.png 753w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755185//image_preview-5-4.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Firefox code>dir()/code> and code>dirxml()/code> double example/figcaption>/figure>\n\n\n\np>Not really that much different other than that Chrome doesn’t show the second object in code>console.dir()/code> like Firefox does. Which makes sense because Chrome is trying to display properties of an object (ignoring the second) while Firefox is just aliasing everything to a code>console.log()/code>. So, for situations like this with objects there is little difference between code>console.log()/code>, code>console.dir()/code>, and code>console.dirxml()/code> in the browsers./p>\n\n\n\np>A useful benefit of code>console.dir()/code> in Chrome that I can point out is how DOM elements are handled. For example, here’s how code>console.log()/code> displays in Chrome and Firefox when given a DOM element./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755186//image_preview-9.png?ssl1 alt classwp-image-303655 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_753/v1582755186//image_preview-9.png 753w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755186//image_preview-9.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome code>console.log()/code> DOM example./figcaption>/figure>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755187//image_preview-2-6.png?ssl1 alt classwp-image-303657 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_754/v1582755187//image_preview-2-6.png 754w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755187//image_preview-2-6.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Firefox code>console.log()/code> DOM example/figcaption>/figure>\n\n\n\np>Now, I’ve always liked how Firefox outputs a DOM element inside a code>console.log()/code>, as it gives you all the properties of that DOM element. So, when I wanted to look up a specific property of a DOM element to manipulate with JavaScript, it’s only a code>console.log()/code> away to find it. Chrome, on the other hand, gives us the HTML code of the DOM element in the code>console.log()/code> just like it would in code>console.dirxml()/code>./p>\n\n\n\np>To get the properties in Chrome, use code>console.dir()/code> with the DOM element. I was quite happy to find that code>console.dir()/code> in Chrome provides the properties of a DOM element just as I came to rely on that information in Firefox./p>\n\n\n\np>As for code>console.dirxml()/code> in Chrome, it can be useful for displaying an HTML element and its children outside of the clutter of the DOM Inspector. You can even edit some of the existing HTML live in the console, but you won\t have the same level of abilities as in the DOM Inspector./p>\n\n\n\nh3>Let’s get together: group(), groupCollapsed(), and groupEnd()/h3>\n\n\n\np>Here’s a simple one: Group different console outputs together to show a form of relationship among them. It is somewhat limited in features so its usefulness will depend a great deal on how you plan to use it. This is the code>console.group()/code> command./p>\n\n\n\npre relJavaScript classwp-block-csstricks-code-block language-javascript data-line>code markuptt>console.group();\nconsole.log(\one\);\nconsole.log(\two\);\nconsole.log(\three\);\nconsole.groupEnd();\n\u2028\nconsole.group(\this is a label\);\nconsole.log(\one\);\nconsole.log(\two\);\nconsole.log(\three\);\nconsole.groupEnd();/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755189//image_preview-3-5.png?ssl1 alt classwp-image-303658 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_753/v1582755189//image_preview-3-5.png 753w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755189//image_preview-3-5.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome code>group()/code> example/figcaption>/figure>\n\n\n\np>In the first block of code we call code>console.group()/code> in its default state, have three logs, and then finally call code>console.groupEnd()/code>. The code>console.groupEnd()/code> simply defines the end of the grouping. The second block has a string as a parameter that essentially becomes the label for that group. Notice that in the first block without a label it just identifies itself as a code>console.group/code> in Chrome while in Firefox it shows as code><no group label>/code>. In most cases, you’ll want a proper label to distinguish between groups./p>\n\n\n\np>Also notice the arrow next to the labels. Clicking on that collapses the group. In the code examples above, if we change code>console.group()/code> to code>console.groupCollapsed()/code>, they start collapsed and must be opened to see the output./p>\n\n\n\np>You can also nest the groups. The code>console.groupEnd()/code> command simply refers to the last opened group./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.group(\outer group\);\nconsole.log(\outer one\);\nconsole.log(\outer two\);\nconsole.group(\inner group\);\nconsole.log(\inner one\);\nconsole.log(\inner two\);\nconsole.log(\inner three\);\nconsole.groupEnd();\nconsole.log(\outer three\);\nconsole.groupEnd();/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755191//image_preview-4-5.png?ssl1 alt classwp-image-303659 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_752/v1582755191//image_preview-4-5.png 752w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755191//image_preview-4-5.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome nested code>group()/code> example/figcaption>/figure>\n\n\n\np>Just as a quick note, if you want the group label to stand out a bit more in a list of output in the console, you can style it just as we did with strings earlier./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.group(\%cstyled group\, \font-size: 20px; color: red;\);\nconsole.log(\one\);\nconsole.log(\two\);\nconsole.log(\three\);\nconsole.groupEnd();/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755192//image_preview-5-5.png?ssl1 alt classwp-image-303660 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_752/v1582755192//image_preview-5-5.png 752w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755192//image_preview-5-5.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome styled code>group()/code> example/figcaption>/figure>\n\n\n\nh3>Have a seat at the: table()/h3>\n\n\n\np>In previous examples, we’ve seen what happens when we put an array or object inside a code>console.log()/code> or code>console.dir()/code>. There’s another option for these data types for a more structured display, which is code>console.table()/code>./p>\n\n\n\np>Here’s a simple example with an array:/p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>let basicArray \n \one\,\n \two\,\n \three\\n;\nconsole.table(basicArray);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755194//image_preview-10.png?ssl1 alt classwp-image-303661 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_751/v1582755194//image_preview-10.png 751w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755194//image_preview-10.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome basic array code>table()/code> example/figcaption>/figure>\n\n\n\np>Here’s the same example in Firefox for comparison./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755196//image_preview-2-7.png?ssl1 alt classwp-image-303662 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_754/v1582755196//image_preview-2-7.png 754w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755196//image_preview-2-7.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Firefox basic array code>table()/code> example/figcaption>/figure>\n\n\n\np>A slight visual difference, but pretty much the same. That said, Chrome does still give you the expandable output under the table, much like you’d see in code>console.log()/code>. Chrome will also provide basic column sorting if you click on the heading./p>\n\n\n\np>The output is similar when passing in an object:/p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>let basicObject {\n one: \one\,\n two: \two\,\n three: \three\\n};\nconsole.table(basicObject);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755197//image_preview-3-6.png?ssl1 alt classwp-image-303663 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_752/v1582755197//image_preview-3-6.png 752w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755197//image_preview-3-6.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome basic object code>table()/code> example/figcaption>/figure>\n\n\n\np>So, that was a pretty simple example with basic outputs. How about something a little more complex and is often used in coding projects? Let’s look at an array of objects./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>let arrayOfObjects \n {\n one: \one\,\n two: \two\,\n three: \three\\n },\n {\n one: \one\,\n two: \two\,\n three: \three\\n },\n {\n one: \one\,\n two: \two\,\n three: \three\\n }\n;\nconsole.table(arrayOfObjects);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755199//image_preview-4-6.png?ssl1 alt classwp-image-303664 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_752/v1582755199//image_preview-4-6.png 752w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755199//image_preview-4-6.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome array of objects code>table()/code> example/figcaption>/figure>\n\n\n\np>As you can see, this gets us a nice layout of objects with repeating keys as column labels. Imagine data along the lines of user information, dates, or whatever might be data often used in loops. Keep in mind that all the keys in each of the objects will be represented as a column, whether there is corresponding keys with data in the other objects. If an object doesn’t have data for a key’s column, it appears as empty./p>\n\n\n\np>An array of arrays is similar to the array of objects. Instead of keys being labels for the columns, it uses the index of the inner arrays as column labels. So if an array has more items than the other arrays, then there will be blank items in the table for those columns. Just like with the array of objects./p>\n\n\n\np>So far, simple arrays and objects have simple output displayed. Even a slightly more complex array of objects still has a solid, useful structure. Things can get a bit different with mixing the data types though./p>\n\n\n\np>For example, an array of arrays where one of the inner array items is an object./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>let arrayOfArraysWithObject \n \one\, \two\, {three: \three\, four: \four\},\n \one\, \two\, {three: \three\, four: \four\},\n \one\, \two\, {three: \three\, four: \four\}\n;\n\nconsole.table(arrayOfArraysWithObject);/code>/pre>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755484//image_preview-5-6.png?ssl1 alt classwp-image-303665 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_752/v1582755484//image_preview-5-6.png 752w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755484//image_preview-5-6.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome array of arrays with object code>table()/code> example/figcaption>/figure>\n\n\n\np>Now, to see what is contained in those objects in the third column, we’ll have to expand that array output below the table. Not that bad, really. Here’s how Firefox handles the same output./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i1.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755485//image_preview-11.png?ssl1 alt classwp-image-303666 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_753/v1582755485//image_preview-11.png 753w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755485//image_preview-11.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Firefox array of array with object code>table()/code> example/figcaption>/figure>\n\n\n\np>Firefox just lets us expand the object within the table./p>\n\n\n\np>How about mixing the data types the other way, where we have an object with arrays as values for each key? It works much the same as the array of arrays. The difference is that each row is labeled with a key instead of the index. Of course, for each level of data type you add to the mix will result in a more complex looking table. /p>\n\n\n\nh3>This is all about: time(), timeLog(), and timeEnd()/h3>\n\n\n\np>Here we have a simple way to log how long something takes to complete. We call code>console.time()/code> with a label, call code>console.timeLog()/code> with the same label for an update, and call code>console.timeEnd()/code> again with the same label to stop the timer./p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.time(\this is a timer\);\nconsole.timeLog(\this is a timer\);\nconsole.timeEnd(\this is a timer\);/code>/pre>\n\n\n\np>The output for Chrome and Firefox is much the same. Here’s an example output with code that logs the time every second for five seconds and then stops./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755487//image_preview-2-9.png?ssl1 alt classwp-image-303668 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_751/v1582755487//image_preview-2-9.png 751w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755487//image_preview-2-9.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome code>time()/code> example/figcaption>/figure>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755489//image_preview-3-7.png?ssl1 alt classwp-image-303669 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_753/v1582755489//image_preview-3-7.png 753w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755489//image_preview-3-7.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Firefox code>time()/code> example/figcaption>/figure>\n\n\n\np>Notice that the reported times are not quite the same, but probably close enough for most requirements. Also, Firefox is nice enough to note that the timer has ended while Chrome requires an assumption once the label stops appearing. The first four lines of output come from the call code>console.timeLog(\this is a timer\);/code> and the last line is from the call to code>console.timeEnd(\this is a timer\);/code>./p>\n\n\n\nh3>Dropping breadcrumbs with: trace()/h3>\n\n\n\np>The code>console.trace()/code> command is actually similar to code>console.error()/code> and code>console.warn()/code>. Calling this command will output a stack trace to the console showing the path through the code to that call. We can even pass it a string as a form of label, but other data types such as arrays or objects can be passed. The behavior of passing data like that is the same as what we would get from a code>console.log()/code> call. It’s a simple way to pass along some information to the console without triggering a more dire looking code>console.error()/code> or code>console.warn()/code> call./p>\n\n\n\nh3>debugger/h3>\n\n\n\np>This is a simple command to trigger a pause in the console’s debugger, if it exists. It is similar to placing a breakpoint in the debugger, or the browser’s equivalent, to cause the same type of pause while executing code. Here’s a simple example:/p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>function whatsInHere() {\n debugger;\n // rest of the code\n}/code>/pre>\n\n\n\np>In this particular example, the open console’s debugger will pause code execution and the browser will open up the source file to show the line of code as soon as the function is called. It could be useful for easy breakpoints with some complicated projects./p>\n\n\n\np>Technically, the code>debugger/code> command isn\t a part of the console object in the browser. It\s a useful feature that the console will respond to from JavaScript code./p>\n\n\n\nh3>Some additional console utilities/h3>\n\n\n\np>That’s a good look at most of the standard commands available to us in the console object. Each of these will work more-or-less the same across modern browsers. There may be some differences between browsers, as we saw in some of the examples. But there are a few more things I’d like to take a moment to point out, as they might prove useful in various ways./p>\n\n\n\np>The following examples can be considered more like console “utilities.” They are not a part of the console object like most of the previous examples. Therefore they are not called with a leading console object reference. These utilities are supported directly by the browsers themselves. They cannot be called from JavaScript code but must be typed directly in the console to be used. In some cases the utility might be unique to a particular browser, in others the utility is supported much the same way in several browsers. Your mileage may vary based on your browser of choice./p>\n\n\n\nh4>$0, $1, $2, $3, $4/h4>\n\n\n\np>These five commands are extremely handy. The first one, code>$0/code>, represents the currently selected element in the DOM inspector. This essentially provides a shortcut instead of having to use more traditional DOM methods, such as code>getElementById/code> or a code>querySelector/code>. You can use it in various ways, within various console commands, or by itself to get information about the currently selected element. For example:/p>\n\n\n\npre rel classwp-block-csstricks-code-block language-none data-line>code markuptt>console.log($0);/code>/pre>\n\n\n\np>The other commands in this set represent elements that were previously selected. Think of them as a form of selection history. code>$1/code> is the previous element, code>$2/code> is the previous before that, and so on. Although the first command is available in Firefox, the commands for previously selected elements are not./p>\n\n\n\nh4>$(‘element’), $$(‘elements’)/h4>\n\n\n\np>If you find yourself typing out code>document.querySelector(\element\)/code> in the console repeatedly, there’s a shortcut. You can just type code>$(\element\)/code> and it performs the same function. The shortcut might remind many of jQuery, but to select multiple elements reminds me of MooTools. To select multiple elements, you’d use code>$$(\elements\)/code> instead of code>document.querySelectorAll(\elements\)/code>./p>\n\n\n\nh4>$x(‘//element’)/h4>\n\n\n\np>This is a shortcut for XPath that will return an array of elements that match the expression. An easy example is code>$x(\//div\)/code>, which will present an array of every div element on the page. This isn’t that much different than using code>$$(\div\)/code> like we did with code>$(\element\)/code>, but there are many options for writing XPath expressions./p>\n\n\n\np>One example of a simple step up in a XPath expression is code>$x(\//divdescendant::span\)/code> (thanks to Neil Erdwien for the correction), which would return the div elements on the page that happen to contain a span element. This is the equivalent of code>:has/code> in CSS Selectors Level 4 draft, which isn’t supported in browsers yet./p>\n\n\n\np>These are just basic examples that only scratch the surface of XPath./p>\n\n\n\nh4>clear()/h4>\n\n\n\np>This is another version of code>console.clear()/code>, but without the “Console was cleared” message./p>\n\n\n\nh4>getEventListeners(object)/h4>\n\n\n\np>This command, when given a DOM element, will report the event listeners registered to that element. For example, using the code>$0/code> example from above we can use code>getEventListeners($0)/code> to get something like this:/p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i0.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755490//image_preview-4-7.png?ssl1 alt classwp-image-303670 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_751/v1582755490//image_preview-4-7.png 751w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755490//image_preview-4-7.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Chrome gcode>etEventListeners()/code> example/figcaption>/figure>\n\n\n\np>Expanding each item in the array provides various information about that event listener. This function isn’t supported in Firefox, but it does offer something similar that can be found in the DOM inspector./p>\n\n\n\nfigure classwp-block-image size-large>img srchttps://i2.wp.com/res.cloudinary.com/css-tricks/image/upload/v1582755492//image_preview-5-7.png?ssl1 alt classwp-image-303671 srcsethttps://res.cloudinary.com/css-tricks/image/upload/c_scale,w_753/v1582755492//image_preview-5-7.png 753w, https://res.cloudinary.com/css-tricks/image/upload/c_scale,w_50/v1582755492//image_preview-5-7.png 50w sizes(min-width: 735px) 864px, 96vw data-recalc-dims1 />figcaption>Firefox DOM Inspector events information./figcaption>/figure>\n\n\n\np>Clicking on the “event” badge next to the element provides a list of events registered to the element. Then each event can be expanded to show the code involved with the event./p>\n\n\n\nh3>That’s it for now!/h3>\n\n\n\np> I’ll end it here, with a large amount of information detailing various commands that can be used in the browser’s console output or with JavaScript. This isn’t em>everything/em> that is possible — there’s simply too much to cover. In some cases, each browser has its own capabilities or utilities that can be leveraged. We looked at the bulk of what we might find in Chrome and Firefox, but there’s likely more out there. Plus, there will always be new features introduced in the future. I invite you to dig deeper to discover more ways to leverage browser DevTools for your coding projects.br>/p>\n,protected:e}},{id:303339,slug:add-background-colors-to-svgs-using-the-rect-element,title:{rendered:Add Background Colors to SVGs Using the “rect” Element},excerpt:{rendered:p>The advantages of using SVGs in web development are well known. SVGs are small in size, can be made quite accessible, are scalable while maintaining their quality, and can be animated. Still, there is a learning curve. Things, like the syntax of SVG, can be a little tricky and having to hand-alter SVG code sometimes …/p>\n,protected:e},date:2020-02-20T07:43:48,tags:9710,469,660,content:{rendered:\np>The advantages of using SVGs in web development are a relnoreferrer noopener target_blank hrefhttps://css-tricks.com/using-svg/>well known/a>. SVGs are small in size, can be made quite accessible, are scalable while maintaining their quality, and can be animated. Still, there is a learning curve. Things, like the syntax of SVG, can be a little tricky and having to hand-alter SVG code sometimes isn’t out of the question./p>\n\n\n\np>Most SVG assets allow styling to be applied in predictable ways. For instance, this circle has a hover state that functions much like any other element in the DOM./p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_ExaMJYL src//codepen.io/anon/embed/ExaMJYL?height250&theme-id1&slug-hashExaMJYL&default-tabresult height250 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed ExaMJYL titleCodePen Embed ExaMJYL classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>However, a problem I\ve encountered on several front-end projects is being provided a strong>sub-optimal/strong> SVG asset by a client, designer, or brand resources site. There isn’t anything “wrong” with these files, but the SVG code requires manual revision to achieve necessary functionality. Instead of requesting new files, it is often easier to tweak them myself. /p>\n\n\n\n\x3c!--more--\x3e\n\n\n\np>Styling SVGs is complicated by the fact that, as XML-based files, they act like HTML in some respects, but not in others. Let’s work with an example provided by a relnoreferrer noopener target_blank hrefhttps://en.instagram-brand.com/assets/icons>Instagram/a> themselves (which is also a relnoreferrer noopener target_blank hrefhttps://commons.wikimedia.org/wiki/File:Instagram_font_awesome.svg>easily findable on Wikipedia/a>). Because the spaces in between paths act as a sort of transparency this image displays whatever background has been applied behind it. /p>\n\n\n\np>Why isn’t there a background color on the SVG so we can apply a color change on hover (e.g. code>svg:hover { background: #888; }/code>)? It’s because the paths fill the reverse of the space you would think they would. The negative space renders whatever sits behind this element (code><body>/code> in the CodePen examples below). Often this is not a problem and may even be desirable for large background designs to ensure organic transitions between content areas. However, because I am using this SVG as a link, I will need to alter the file so that I can style the space behind it. /p>\n\n\n\npre relSVG classlanguage-svg data-line classwp-block-csstricks-code-block>code markuptt><svg xmlnshttp://www.w3.org/2000/svg width24 height24 viewBox0 0 24 24>\n <title>Instagram</title>\n <path d... transformtranslate(0 0) fill#fff/>\n <path d... transformtranslate(0 0) fill#fff/>\n <path d... transformtranslate(0 0) fill#fff/>\n</svg>/code>/pre>\n\n\n\np>The Instagram logo is a perfect example of an awkward SVG file that requires more CSS finesse than most. Again, there is nothing em>wrong/em> with this SVG, but it presents some challenges for styling. In order to add a hover state that alters the background, we will need to change the code above./p>\n\n\n\np>There are several ways to go about this, but the easiest fix is to add another element behind the image. Because the Instagram icon is rectangular, we can add a code><rect/code>> element behind the three foreground paths that comprise this SVG. If the logo was circular or oval, I would have used the code><circle>/code> or code><ellipse>/code> element. Be sure to set a height and width to match the code>viewBox/code> when adding this type of element, and use the code>rx/code> value to round the corners as needed. Rather than adding a class or fill to every path in the SVG element, we can target the code><rect>/code> and code><path>/code> elements in the CSS file. /p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_xxbRoxL src//codepen.io/anon/embed/xxbRoxL?height250&theme-id1&slug-hashxxbRoxL&default-tabhtml,result height250 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed xxbRoxL titleCodePen Embed xxbRoxL classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>The advantage of this approach is its simplicity. Instead of having to alter multiple files or use JavaScript or third-party JavaScript libraries, we can add one line of code to the SVG code block and style it. /p>\n\n\n\np>If, for some reason, you need or just prefer to leave the SVG file alone, you can revise the CSS to achieve similar functionality. /p>\n\n\n\np>We could add a code>background/code> property on the code>social-link/code> class but, for this tutorial, I will instead use the slightly more complicated, but equally effective, strategy of revising an SVG by applying a pseudo-element to it. In the example below, I have used the code>::before/code> pseudo-class to add a shape and the code>opacity/code> property to make it visible on hover. To avoid having this shape leave a border around the icon, I have made it slightly smaller than the SVG using the code>height/code> and code>width/code> properties (code>calc(100% - 2px)/code>). Then I center the pseudo-element behind the SVG and match the transition property for both element and pseudo-element./p>\n\n\n\npre relCSS classwp-block-csstricks-code-block language-css data-line>code markuptt>/* Sets the link\s dimensions */\n.social-link {\n display: block;\n height: 24px;\n position: relative;\n width: 24px;\n}\n\n/* Targets the pseudo-element to create a new layer */\n.social-link::before {\n background: #fff;\n border-radius: 2px;\n content: ;\n display: block;\n height: calc(100% - 2px);\n opacity: 0;\n position: absolute;\n transition: all 0.2s ease-in-out;\n width: calc(100% - 2px);\n}\n\n/* Changes the background color of the pseudo-element on hover and focus */\n.social-link::before:hover, .social-link::before:focus {\n background: #000;\n}\n\n/* Makes sure the actual SVG element is layered on top of the pseudo-element */\n.social-link svg {\n position: relative;\n z-index: 1;\n}\n\n/* Makes the background-color transition smooth */\n.social-link svg path {\n transition: all 0.2s ease-in-out;\n}\n\n/* SVG paths are initially white */\n.social-link path {\n fill: #fff;\n}\n\n/* The pseudo-elememt comes into full view on hover and focus */\n.social-link:hover::before, .social-link:focus::before {\n opacity: 1;\n}\n\n/* Fills the SVG paths to black on hover and focus */\n.social-link:hover svg path, .social-link:focus svg path {\n fill: #000;\n}/code>/pre>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_MWYPPxO src//codepen.io/anon/embed/MWYPPxO?height250&theme-id1&slug-hashMWYPPxO&default-tabcss,result height250 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed MWYPPxO titleCodePen Embed MWYPPxO classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>I recommend the above strategies for a quick fix because using vanilla JavaScript or a JavaScript library like a relnoreferrer noopener target_blank hrefhttps://maxwellito.github.io/vivus/>vivus.js/a> or a relnoreferrer noopener target_blank hrefhttp://raphaeljs.com/>raphaeljs/a> is overkill for adding a hover state to an SVG in most cases. However, there are times when modifying an SVG using JavaScript is preferable. Because JavaScript is undoubtedly the most flexible method to change styles, let’s examine what this might look like./p>\n\n\n\np>My example separates the JavaScript file, but if you want to add JavaScript inside the SVG element itself, you will need to add a code><script>/code> element, just like an HTML file. Be sure to add a CDATA marker to your code><script>/code> element to ensure it is parsed as XML./p>\n\n\n\ndiv classwp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper>iframe idcp_embed_bGNmmJB src//codepen.io/anon/embed/bGNmmJB?height250&theme-id1&slug-hashbGNmmJB&default-tabjs,result height250 scrollingno frameborder0 allowfullscreen allowpaymentrequest nameCodePen Embed bGNmmJB titleCodePen Embed bGNmmJB classcp_embed_iframe stylewidth:100%;overflow:hidden>CodePen Embed Fallback/iframe>/div>\n\n\n\np>I’m using jQuery to simplify things a bit and keep CSS as minimal as possible, although for clarity sake, I have added a code>background/code> property on the code>social-link/code> class in the CSS file rather than adding it via JavaScript. Notice that this solution targets code>svg path/code> when altering the CSS method rather than assigning a class to these paths because, in this case, each path should be treated the same./p>\n\n\n\np>There are many many ways to style SVGs, but the examples collected in this article are useful and extensible. Strategies for altering SVG files need to be evaluated by an app’s full functionality, but I suspect most front-end developers will find that the code><rect>/code> element offers the simplest and most readable solution./p>\n\n\n\nh1>Acknowledgements/h1>\n\n\n\np>Many thanks to a relnoreferrer noopener target_blank hrefhttp://joeessey.com/>Joe Essey/a> and my front-end pals at Nebo Agency a relnoreferrer noopener target_blank hrefhttp://allisonllewis.com/>Allison Lewis/a> and a relnoreferrer noopener target_blank hrefhttp://helloimnile.com/>Nile Livingston/a> (check out Nile’s article, a relnoreferrer noopener target_blank hrefhttps://www.neboagency.com/labs/svgs-for-the-web/>“SVGs for the Web”/a>). /p>\n,protected:e}},{id:303786,slug:seen-by-indeed,title:{rendered:Seen by Indeed},excerpt:{rendered:p>Are you looking for a tech job where you clock in, or for a career where you’ll be seen? Seen by Indeed is a matching service for software engineers, product managers and other tech pros that sorts through thousands of companies — like Twilio, Overstock, VRBO, and PayPal — and matches tech talent like you to …/p>\n,protected:e},date:2020-02-20T07:43:38,tags:,content:{rendered:\np>Are you looking for a tech job where you clock in, or for a career where you’ll be em>seen/em>?/p>\n\n\n\np>a hrefhttps://synd.co/2UKNo3L>Seen by Indeed/a> is a matching service for software engineers, product managers and other tech pros that sorts through em>thousands/em> of companies -- like Twilio, Overstock, VRBO, and PayPal -- and matches tech talent like you to the role that’ll take you further. Not only does Seen by Indeed match on things like skills, experience and salary, but we’re with you every step of the way with free one-on-one career coaching, resume reviews and in-depth resources./p>\n\n\n\np>So, whether you need negotiation tips, networking strategies or just want to talk to someone about your career, a hrefhttps://synd.co/2UKNo3L>Seen by Indeed/a> has you covered. In fact, you can start by a hrefhttps://synd.co/2UKNo3L>getting a free resume review/a> that covers formatting, how to beat the resume-screening bots and personalized tips on how to show yourself off./p>\n\n\n\np>What are you waiting for? Put Indeed’s new tech-focused matching platform to use to move up in your career./p>\n,protected:e}},{id:303271,slug:footnote-characters,title:{rendered:Footnote Characters},excerpt:{rendered:p>There are special superset number characters that are sometimes perfect for footnotes. Here they are: ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ I generally prefer to superscript the number myself, like:/p>\n,protected:e},date:2020-02-19T17:47:26,tags:11523,1390,content:{rendered:\np>There are special superset number characters that are sometimes perfect for footnotes. Here they are:/p>\n\n\n\np>¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹/p>\n\n\n\np>I generally prefer to superscript the number myself, like:/p>\n\n\n\n\x3c!--more--\x3e\n\n\n\npre relHTML classlanguage-markup data-line classwp-block-csstricks-code-block>code markuptt><p>This next word<sup>1</sup> has a footnote.</p>/code>/pre>\n\n\n\np>That way I can select it in CSS or JavaScript in case I want to do something special with it. /p>\n\n\n\np>You\d probably add an anchor link around that as well to link to an ID elsewhere on the page that explains the footnote. /p>\n\n\n\np>But sometimes it just isn\t practical or possible to use HTML as you author a bit of text. As I type, I\m writing in the WordPress Gutenberg editor. I can write in HTML block if I want, but it\s much more practical to use the default paragraph blocks, which have options for stuff like bold, italic, and strikethrough, but not for superscript. I don\t really wanna convert a block to HTML just to use a superscript number. So, a special Unicode charactera href#fn:1>¹/a> it is. /p>\n\n\n\ndiv classwp-block-group footnotes idfn:1>div classwp-block-group__inner-container>\nol>li>Another thing the Gutenberg editor can\t do is add an ID to a link, so it\s not really practical for me to offer a jump back to the footnote link down here. Sad face./li>/ol>\n/div>/div>\n\n\n\np>/p>\n,protected:e}},{id:303706,slug:do-this-to-improve-image-loading-on-your-website,title:{rendered:Do This to Improve Image Loading on Your Website},excerpt:{rendered:p>In the video embedded below, Jen Simmons explains how to improve image loading by using width and height attributes. The issue is that there’s a lot of jank when an image is first loaded because an img will naturally have a height of 0 before the image asset has been successfully downloaded by the browser. …/p>\n,protected:e},date:2020-02-19T17:47:12,tags:1268,585,592,content:{rendered:\np>In the video embedded below, Jen Simmons explains how to improve image loading by using width and height attributes. The issue is that there’s a lot of jank when an image is first loaded because an code>img/code> will naturally have a height of code>0/code> before the image asset has been successfully downloaded by the browser. Then it needs to repaint the page after that which pushes all the content around. I’ve definitely seen this problem em>a lot/em> on big news websites. /p>\n\n\n\np>Anyway, Jen is recommending that we should add code>height/code> and code>width/code> attributes to images like so:/p>\n\n\n\npre relHTML classlanguage-markup data-line classwp-block-csstricks-code-block>code markuptt><img srcdog.png height400 width1000 altA cool dog />/code>/pre>\n\n\n\np>This is because Firefox & Chrome will now take those values into consideration and remove all the jank before the image has loaded, em>even when you override those values in CSS with a fluid width and thus unknown height/em>. That means content will always stay in the same position, even if the image hasn’t loaded yet. In the past, I’ve worked on a bunch of projects where I’ve placed images lower down the page simply because I want to prevent this sort of jank. I reckon this fixes that problem quite nicely./p>\n\n\n\nfigure classwp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio>div classwp-block-embed__wrapper>\niframe titleDo This to Improve Image Loading on Your Website width500 height281 srchttps://www.youtube.com/embed/4-d_SoCHeWE?featureoembed frameborder0 allowaccelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture allowfullscreen>/iframe>\n/div>/figure>\n,protected:e}}},serverRendered:!0}}(!1)/script>script src/_nuxt/7e2805414fd369c0a42a.js defer>/script>script src/_nuxt/9a9898ea5b57175815e3.js defer>/script>script src/_nuxt/afa78572961c8cafe1b7.js defer>/script>script src/_nuxt/273afb766edb22194650.js defer>/script> /body>/html>
View on OTX
|
View on ThreatMiner
Please enable JavaScript to view the
comments powered by Disqus.
Data with thanks to
AlienVault OTX
,
VirusTotal
,
Malwr
and
others
. [
Sitemap
]