<div class="card" data-component="card">
<header>
<h1>Scoped Styling with <code>@scope</code></h1>
</header>
<div class="card__content">
<h2>An image child</h2>
<p><img src="https://assets.codepen.io/89905/matroshka-02.svg" alt="" title="" width="222" height="184" draggable="false" class="float-right"> This is a piece of text with an image next to it. The image is a child of the card component but not of the carousel component. Note how the image is targeted by the Scoped CSS: it has a border added to it.</p>
<h2>Nested Carousel</h2>
<p>Embedded below is a carousel component, marked with the <code>data-component</code> attribute. The images contained in this component are not targeted by the Scoped CSS. This because of the <em>scoping limit</em> that is being used.</p>
<div data-component="carousel">
<ul class="entries" tabindex="0">
<li><a name="carousel_01"><img src="https://assets.codepen.io/89905/matroshka-01.svg" alt="" title="" width="222" height="184" draggable="false"></a></li>
<li><a name="carousel_02"><img src="https://assets.codepen.io/89905/matroshka-02.svg" alt="" title="" width="222" height="184" draggable="false"></a></li>
<li><a name="carousel_03"><img src="https://assets.codepen.io/89905/matroshka-03.svg" alt="" title="" width="222" height="184" draggable="false"></a></li>
<li><a name="carousel_04"><img src="https://assets.codepen.io/89905/matroshka-04.svg" alt="" title="" width="222" height="184" draggable="false"></a></li>
<li><a name="carousel_05"><img src="https://assets.codepen.io/89905/matroshka-05.svg" alt="" title="" width="222" height="184" draggable="false"></a></li>
</ul>
<ul class="bullets">
<li><a href="#carousel_01"><span class="sr-only">Photo 1</span></a></li>
<li><a href="#carousel_02"><span class="sr-only">Photo 2</span></a></li>
<li><a href="#carousel_03"><span class="sr-only">Photo 3</span></a></li>
<li><a href="#carousel_04"><span class="sr-only">Photo 4</span></a></li>
<li><a href="#carousel_05"><span class="sr-only">Photo 5</span></a></li>
</ul>
</div>
<h2>Another image child</h2>
<p><img src="https://assets.codepen.io/89905/matroshka-01.svg" alt="" title="" width="222" height="184" draggable="false" class="float-left"> And here’s another image in the card component. It, as well, is targeted by the scoped CSS.</p>
</div>
<footer>
This demo is part of <a href="https://goo.gle/css-wrapped-2023" target="_top">#CSSWrapped2023</a>
</footer>
</div>
</div>
/* Card Component */
.card {
border-radius: 0.5em;
background: transparent
linear-gradient(to bottom right, #ff00fa 0%, #0ff 100%);
border: 0.25em solid #6300ff;
> * {
padding: 1rem;
}
.card__content {
background: white;
border-top: 0.25em solid #6300ff;
border-bottom: 0.25em solid #6300ff;
}
& footer {
color: white;
}
}
/* Only match elements in the card component, but don’t target those in nested components */
@scope (.card) to ([data-component]) {
img {
border: 0.25em solid #6300ff;
border-radius: 0.5em;
}
}
/* Carousel Component */
[data-component="carousel"] {
border-radius: 0.5em;
border: 0.25em solid #6300ff;
position: relative;
margin: 1em auto;
background: white;
timeline-scope: --carousel;
&:hover,
&:has(.entries:focus) {
border-color: #ff00fa;
}
.entries {
display: flex;
width: 100%;
flex-direction: row;
overflow-x: scroll;
scroll-snap-type: x mandatory;
scrollbar-width: none;
scroll-behavior: smooth;
padding: 1em 1em 2.5em 1em;
scroll-timeline: --carousel x;
&:focus {
outline: none;
}
> * {
scroll-snap-align: center;
flex: 100% 0 0;
display: grid;
place-content: center;
}
& img {
display: block;
}
}
.bullets {
display: flex;
flex-direction: row;
gap: 0.25em;
position: absolute;
bottom: 1em;
left: 50%;
translate: -50% 0;
& li {
&:nth-child(1) {
--i: 1;
}
&:nth-child(2) {
--i: 2;
}
&:nth-child(3) {
--i: 3;
}
&:nth-child(4) {
--i: 4;
}
&:nth-child(5) {
--i: 5;
}
}
& a {
display: block;
width: 0.5em;
aspect-ratio: 1;
background: #6300ff;
border-radius: 50%;
animation: colorize-dot linear;
animation-timeline: --carousel;
animation-range: calc((var(--i) - 1) * 20%) calc(var(--i) * 20%);
}
}
}
@keyframes colorize-dot {
0%,
100% {
background: #ff00fa;
}
}
@layer reset {
*,
*:after,
*:before {
box-sizing: border-box;
}
* {
margin: 0;
padding: 0;
}
ul[class] {
list-style: none;
}
label {
cursor: pointer;
max-width: max-content;
user-select: none;
}
}
@layer baselayout {
html {
margin: auto;
line-height: 1.5;
font-size: 1.25em;
font-family: "Syne", sans-serif;
min-height: 100%;
background: white;
}
body {
width: 100%;
max-width: 75ch;
margin: 0 auto;
min-height: 100dvh;
padding: 2em;
}
h1,
h2 {
font-family: "Anybody", sans-serif;
text-decoration: underline;
text-decoration-color: hsl(156deg 100% 50% / 50%);
text-decoration-thickness: 0.2rem;
text-decoration-style: wavy;
text-decoration-skip-ink: none;
}
h2,
p {
margin-bottom: 1em;
text-wrap: balance;
}
h2:not(h2:first-child) {
margin-top: 2em;
}
a {
color: inherit;
}
}
@layer utilities {
.float-right {
float: right;
margin-left: 0.5em;
}
.float-left {
float: left;
margin-right: 0.5em;
}
*:has(> .float-right, > .float-left) {
display: flow-root;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.