<!-- .slide: data-background-color="var(--selective)" --> <div class="content-warning"> <div>Content</div> <div>Advisory</div> <div>Experimental Content</div> </div> --- <img src="/shared/images/remote-qr.svg" alt="" /> ## tinyurl.com/jh3y-remote --- <!-- End Deck --><br><!-- .slide: class="title-slide" data-background-color="var(--brand)" --> ###### State of the Browser 2022 ## Speedy Dev Insights <div class="volume-title">Vol. I</div> --- <!-- End Slide --><br><!-- .slide: class="title-slide title-slide--left" data-background-color="var(--white)" --> ## I'm Jhey Tompkins #### Developer Relations Engineer<br>@ <span class="googley">Google</span> <!-- <img class="polaroid" src="/shared/images/bear-baby-chilling.jpg" width="300" /> --> <img class="polaroid" src="/shared/images/baby-photo--resized.jpeg" width="300" /> --- <!-- End Slide --><br><!-- .slide: class="title-slide" data-background-color="var(--black)"--> ## A series of <span style="color: var(--blueberry)">micro</span> presentations about things <span style="color: var(--selective)">coming</span> to the <span style="color: var(--chateau)">Web Platform</span> ✨ --- <!-- End Slide --><br><!-- .slide: data-background-color="var(--white)" --> <div class="block-reveal"> # Here # we # gooooo! </div> <img class="watermark-bear" src="/shared/images/bear-2022--black.png" alt=""/> --- <!-- End Slide --><br><!-- .slide: data-background-color="var(--black)" data-background-video="/shared/video/family.mp4" data-background-video-loop="true" data-background-size="contain" data-background-video-muted="true" --> --- <!-- .slide: class="title-slide" data-background-color="var(--fuschia)" --> ## CSS :has --- <!-- .slide: data-background-color="var(--black)" --> <div class="support-grid"> <span class="browser-logo" data-browser="chrome"></span> <span class="browser-logo" data-browser="edge"></span> <span class="browser-logo" data-browser="safari"></span> <span class="browser-logo" data-browser="firefox"></span> <span class="browser-version" data-supported>105</span> <span class="browser-version" data-supported>105</span> <span class="browser-version" data-supported>15.4</span> <span class="browser-version"> <span class="material-symbols-outlined"> flag </span> </span> </div> --- <!-- .slide: data-background-color="var(--white)" --> ```css [] <target>:has(<condition>) { <styles> } ``` --- <!-- .slide: data-background-color="var(--selective)" --> <div> ```css [] .everybody:has(.a-good-time) { animation: party-like-its 1999s forwards; } .jeff:has(~ .some-distant-relative) { animation: visit 10000s; } ``` </div> ```html [] <!-- Selected! ✅--> <div class="everybody"> <div class="body body--at-state-of-the-browser"> <div class="a-good-time"></div> </div> </div> <!-- Not Selected ❌--> <div class="everybody"></div> <!-- Selected! ✅--> <div class="jeff"></div> <div class="some-distance"></div> <div class="some-distant-relative"></div> ``` --- <!-- .slide: class="title-slide" data-background-color="var(--fuschia)" --> ## Break the mental model <span class="flipper-wrapper"><span class="flipper">🛹</span></span> --- <!-- .slide: data-background-color="var(--selective)" --> ## use cases for days ```css [] /* Change the grid layout based on content */ .card:has(.card__image) { grid-template-columns: 100px 1fr; } /* Full width card when containing feature */ .card:has(.card__feature) { grid-column: 1 / -1; } /* Non icon links */ a:not(:has(> svg)) { ... } /* Update the :root based on some state change */ :root:has([aria-pressed=true]) { … } /* Select the .container that has an odd number of children */ .container:has(> .container__item:last-of-type:nth-of-type(odd)) { ... } /* Custom elements are supported too */ main:has(todo-list) { ... } ``` <sub>There are a bunch of examples in [":has(): the family selector"](https://developer.chrome.com/blog/has-m105) over on [developer.chrome.com](https://developer.chrome.com/blog/has-m105).</sub> --- <!-- .slide: data-background-color="var(--brand)" class="title-slide title-slide--left" --> ## Let's play with<br>form state! --- <!-- .slide: data-background-iframe="/demos/css-has/has-forms/with-whimsy" data-background-interactive --> --- <!-- .slide: data-background-color="var(--cinnabar)" --> ```css [] :root { --dark-mode: 0; --text-1: var(--gray-9); --text-2: var(--gray-8); } /* Don't do it with a checkbox 🙏 */ :root:has(.theme-toggle[aria-pressed=true]) { --dark-mode: 1; --text-1: var(--gray-0); --text-2: var(--gray-1); } body { color: var(--text-2); } h1 { color: var(--text-1); } ``` --- <!-- .slide: data-background-iframe="/demos/css-has/has-dark-mode-animations" data-background-interactive --> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/css-has/has-calendar" data-background-interactive --> --- <!-- .slide: data-background-color="var(--chateau)" --> ```html [] <table> <tr> <td class="calendar__cell"> <span class="calendar__number">30</span> <input type="radio" class="sr-only" name="from" id="from-09-30" /> <input type="radio" class="sr-only" name="to" id="to-09-30" /> <label for="from-09-30">from 09-30</label> <label for="to-09-30">to 09-30</label> </td> <td class="calendar__cell"> <span class="calendar__number">1</span> <input type="radio" class="sr-only" name="from" id="from-10-01" /> <input type="radio" class="sr-only" name="to" id="to-10-01" /> <label for="from-10-01">from 10-01</label> <label for="to-10-01">to 10-01</label> </td> </tr> </table> ``` --- <!-- .slide: data-background-color="var(--fuschia)" --> ```css [] .calendar__cell:has(:checked) { --background: var(--primary); --alpha: 1; --color: var(--light); } .calendar:has([id*=from]:checked):not(:has([id*=to]:checked)):has(.calendar__cell:hover) tr:has(:checked) ~ tr:has(:hover) .calendar__cell:has(~ .calendar__cell:hover) { --background: var(--potential); --alpha: 1; } .calendar:has([id*=from]:checked):has([id*=to]:checked) tr:has([id*=from]:checked):has(~ tr .calendar__cell > :checked) .calendar__cell:has([id*=from]:checked) ~ .calendar__cell:not(:hover) { --background: var(--in-range); --alpha: 1; --color: var(--light); } ``` --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/css-has/has-connect-4" data-background-interactive --> --- <!-- .slide: data-background-color="var(--selective)" --> ```html [|3,4,26,27] <div class="board__column"> <div class="board__cell move-6" style="--row: 1;"> <input type="checkbox" id="s-1" data-row="s-1" data-column="s-1"/> <input type="checkbox" id="p-1" data-row="p-1" data-column="p-1"/> <div class="board__disc disc"> <div class="disc__piece"> </div> </div> </div> <div class="board__cell move-5" style="--row: 2;"> <input type="checkbox" id="s-2" data-row="s-2" data-column="s-1"/> <input type="checkbox" id="p-2" data-row="p-2" data-column="p-1"/> <div class="board__disc disc"> <div class="disc__piece"> </div> </div> </div> <!-- Other cells --> </div> <div class="board__labels move-6" data-for="move-6" style="--row: 1;"> <div class="cuboid"> <div class="cuboid__side"></div> <div class="cuboid__side"></div> <div class="cuboid__side"> <div class="move-controls"> <label class="board__move" for="s-1"></label> <label class="board__move" for="p-1"></label> </div> </div> </div> </div> ``` --- <!-- .slide: data-background-color="var(--cinnabar)" --> ```css [] /* Horizontal */ .board__column:has([data-row=p-1]:checked) + .board__column:has([data-row=p-1]:checked) + .board__column:has([data-row=p-1]:checked) + .board__column:has([data-row=p-1]:checked) ~ .win, /* Diagonal */ .board__column:has([data-row=p-1]:checked) + .board__column:has([data-row=p-2]:checked) + .board__column:has([data-row=p-3]:checked) + .board__column:has([data-row=p-4]:checked) ~ .win { display: block; --winner: var(--primary); --show-win: 1; } ``` --- <!-- .slide: class="title-slide title-slide--bottom" data-background-color="var(--fuschia)" --> ## But, really? How much wood could a woodchuck chuck if a woodchuck could chuck wood? --- <!-- .slide: data-background-color="var(--blueberry)" --> <div class="code-grid" style="display: grid; grid-auto-flow: column; gap: 2rem; align-items: center; justify-content: center;"> ```js [] const PARTICLES = [ { trigger: 'wood', emoji: '🌴', }, { trigger: 'chuck', emoji: '🪓' } ] ``` ```css [] .wood ~ .chuck { animation: chuck 0.5s infinite; } @keyframes chuck { 50% { transform: rotate(-45deg); } } .wood:has(+ .chuck) { animation: chucked 1s forwards; } @keyframes chucked { to { transform: rotate(-90deg); } } ``` </div> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/css-has/has-woodchuck" data-background-interactive --> --- <!-- End Section<br><!-- .slide: data-background-video="/shared/video/pop-up-stack.mp4" data-background-video-loop="true" data-background-video-muted="true" data-background-video-size="cover" --> --- <!-- .slide: class="title-slide title-slide--top" data-background-color="var(--spearmint)" --> ## Open UI Pop-up --- <!-- .slide: data-background-color="var(--white)" --> <div class="support-grid"> <span class="browser-logo" data-browser="canary"></span> <span class="browser-logo" data-browser="chrome"></span> <span class="browser-logo" data-browser="edge"></span> <span class="browser-logo" data-browser="safari"></span> <span class="browser-logo" data-browser="firefox"></span> <span class="browser-version" data-supported> <span class="material-symbols-outlined"> flag </span> </span> <span class="browser-version">×</span> <span class="browser-version">×</span> <span class="browser-version">×</span> <span class="browser-version">×</span> </div> --- <!-- .slide: class="title-slide title-slide--top" data-background-color="var(--black)" --> ## The goal of the <span style="color: var(--citric);">Open UI</span> initiative is to make it <span style="color: var(--blueberry)">easier</span> for developers to make <span style="color: var(--fuschia);">great user experiences</span> --- <!-- .slide: class="title-slide title-slide--bottom" data-background-image="/shared/images/king.jpg" data-background-opacity="0.4" --> ## What's the top layer? A place outside of the <span style="background-color: var(--cinnabar);">document</span> flow. A place where <span style="background-color: var(--chateau);">z-index</span> has no effect. Where every element has a styleable <span style="background-color: var(--selective);">::backdrop</span>. --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/with-backdrop" --> --- <!-- .slide: data-background-color="var(--white)" --> <ul class="bullets"> <li>Hidden by default</li> <li>No JavaScript</li> <li>No z-index fighting</li> <li>Light dismiss</li> </ul> --- <!-- .slide: data-background-color="var(--white)" data-background-iframe="/demos/openui-pop-ups/nav-drawer" --> --- <!-- .slide: data-background-color="var(--citric)" --> ```css [|17, 18, 19] [popover] { left: 100%; width: var(--nav-width); transition: transform 0.2s; transform: translateX(calc(var(--open, 0) * -100%)); } [popover]::backdrop { transition: opacity 0.2s; opacity: var(--open, 0); } [popover]:open, [popover]:open::backdrop { --open: 1; } body:has([popover]:open) { transform: translateX(calc(var(--nav-width) * -1)); } ``` --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/webcam-throw" --> --- <!-- .slide: style="--code-size: 0.325em;" data-background-color="var(--spearmint)" --> ```html [] <button popover="manual" defaultopen popovertoggletarget="menu" > <i class="material-icons">add</i> </button> <div id="menu" class="fab__menu" popover="auto" style="--count: 3"> <ul class="fab__menu-items"> <li class="fab__menu-item"> <button autofocus class="fab" style="--index: 0" popoverhidetarget="menu" > <i class="material-icons">chat</i> </button> </li> <li class="fab__menu-item"> <button class="fab" style="--index: 1" popoverhidetarget="menu" > <i class="material-icons">photo_camera</i> </button> </li> <li class="fab__menu-item"> <button class="fab" style="--index: 2" popoverhidetarget="menu" > <i class="material-icons">pin_drop</i> </button> </li> </ul> </div> ``` --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/poppers-outro" --> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/openui-pop-ups/error-heaven" --> --- <!-- End Section<br><!-- .slide: data-background-video="/shared/video/doom-scroll.mp4" data-background-video-loop="true" data-background-video-muted="true" data-background-video-size="cover" --> --- <!-- .slide: class="title-slide title-slide--bottom" data-background-color="var(--citric)"--> <!-- If you want to do everything in Canary with the polyfill --> <!-- open -a /Applications/Google\ Chrome\ Canary.app --args --disable-blink-features=CSSScrollTimeline,ScrollTimeline --> ## Scroll Linked Animations --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/scroll-linked-animations/column-parallax" --> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/scroll-linked-animations/snap-directions-root" --> --- <!-- .slide: data-background-color="hsl(0 0% 0%)" --> <div class="support-grid"> <span class="browser-logo" data-browser="chrome"></span> <span class="browser-logo" data-browser="edge"></span> <span class="browser-logo" data-browser="safari"></span> <span class="browser-logo" data-browser="firefox"></span> <span class="browser-version" data-supported> <span class="material-symbols-outlined"> format_paint </span> </span> <span class="browser-version" data-supported> <span class="material-symbols-outlined"> format_paint </span> </span> <span class="browser-version" data-supported> <span class="material-symbols-outlined"> format_paint </span> </span> <span class="browser-version" data-supported> <span class="material-symbols-outlined"> format_paint </span> </span> </div> --- <!-- .slide: data-background-color="var(--selective)" --> ```css [|3,4,9,22|10,11,12] /* ViewTimeline */ section { view-timeline-name: --section; view-timeline-axis: block; } img { transform: translateY(100%); animation: parallax both linear; animation-timeline: --section; /* Likely to change */ animation-delay: cover 95%; animation-end-delay: exit 75%; } @keyframes parallax { to { transform: translateY(0%); } } /* ScrollTimeline */ .progress { animation: progress both linear; animation-timeline: scroll(root); } @keyframes progress { to { rotate: 360deg; } } ``` <sub>You can use this with JavaScript's Web Animations API too!</sub> --- <!-- .slide: class="title-slide title-slide--left" data-background-color="var(--blueberry)" --> ## Let's Make an<br>Image reveal! --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/scroll-linked-animations/image-reveals" --> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/scroll-linked-animations/tokyo-scroll" --> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/scroll-linked-animations/this-is-a-box" --> --- <!-- .slide: data-background-color="hsl(0 0% 0%)" data-background-iframe="/demos/scroll-linked-animations/snap-directions-root" --> --- <!-- ## Micro interactions --- --> <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/scroll-linked-animations/search-micro" --> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/scroll-linked-animations/avatar-micro" --> --- <!-- .slide: data-background-iframe="/demos/scroll-linked-animations/prototype-book" --> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/chrometober-2022/index.html" --> --- <!-- .slide: data-background-video="/shared/video/peter.mp4" data-background-video-loop="true" data-background-video-muted="true" data-background-size="contain" data-background-color="var(--spearmint)"--> --- <!-- .slide: data-background-color="hsl(0 0% 100%)" data-background-iframe="/demos/scroll-linked-animations/peters-blinds-root" --> --- <!-- End Section<br> <!-- .slide: class="title-slide title-slide--top" data-background-color="var(--brand)" --> ## That's it. --- <!-- .slide: class="title-slide title-slide--top" data-background-color="var(--black)" --> ## <span style="color: var(--selective)">We</span>'re here to <span style="color: var(--chateau)">help</span> <img class="chrome-logo" src="/shared/images/chrome-logo.svg"> --- <!-- End Section<br><!-- .slide: data-background-video="/shared/video/jhey-card-sunglasses.mp4" data-background-video-loop="true" data-background-video-muted="true" data-background-video-size="cover" --> <h2 class="outro-cheers">Cheers</h2> <!-- End Deck --><br>