Datavisualisering (CSS og SVG)
Det handler ikke kun om at vise data men om at designe den måde, data forstås på.
Procentcirkler
Vores værktøjkasse
attr()
mm.
shape()
Gradienter
offset-path
<path>
<circle>
pathLength
stroke-dasharray
stroke-dashoffset
border-area
Pseudo-elementer
a::after {
content: '(opens in new tab)';
}::before, ::after
a[href^="http"]::after {
content: '(opens in new tab)';
}::before, ::after
::before, ::after
a[href^="http"]::after {
content: '(opens in new tab)';
}Øvelse
nav.innerHTML += `<a href=${c.link}>${c.name}</a>` + " / ";Øvelse
Øvelse
nav.innerHTML += `<a href=${c.link}>${c.name}</a>` + " / ";Øvelse
li + li::before {
content: '/';
}Øvelse
li + li::before {
content: '/';
}li:has(a)::after {
content: '/';
}li:has(+ li)::after {
content: '/';
}li:not(:last-child)::after {
content: '/';
}:not(:first-child)::before {
content: '/';
}Fra Temaopgaven
Øvelse
Øvelse
Koniske, lineære, radiale
Koniske, lineære, radiale
.parent {
.child {
offset-path: border-box;
}
}10%20%30%40%50%60%70%100%<article>
<div></div>
</article>article {
display: grid;
grid-template-columns:
repeat(8, 1fr);
height: 300px;
}
div:nth-child(1) {
height: 100%;
}
div:nth-child(2) {
height: 70%;
}
...<article>
<div></div>
<div></div>
...
</article>Ikke så fleksibelt
10%20%30%40%50%60%70%100%article {
display: grid;
grid-template-columns:
repeat(8, 1fr);
}
div:nth-child(1) {
height: 100%;
}
div:nth-child(2) {
height: 70%;
}
...<article>
<div style="height: 100%"></div>
<div style="height: 70%"></div>
...
</article>Data kommer typisk fra JS
10%20%30%40%50%60%70%100%bar.style.height = `${percent}%`div {
height: var(--height, 0%);
}<article>
<div style="--height: 100%"></div>
<div style="--height: 70%"></div>
...
</article>Det kunne ligeså godt se sådan ud
10%20%30%40%50%60%70%100%bar.style.setProperty("--height", `${percent}%`)<article>
<div data-percent="100"></div>
<div data-percent="70"></div>
...
</article>Eller sådan her
(en moderne løsning)
div {
height: attr(data-percent %), 0%);
}10%20%30%40%50%60%70%100%bar.dataset.percent = `${percent}%`div {
width: attr(data-length type(<length>));
&::after {
content: attr(data-length);
}
}attr(data-number type(<number>), 0)
<div data-length="5rem"></div>Hent og brug værdier fra attributter
div {
width: attr(data-length type(<length>));
&::after {
content: attr(data-length);
}
}Units vs. Types
Types of type()
<angle>
<color>
<custom-ident>
<image>
<integer>
<length>
<length-percentage>
<number>
<percentage>
<time>
og calc()
div {
height: attr(data-percent %), 0%);
}.bars {
display: grid;
grid-template-columns: repeat(8, 1fr);
height: 300px;
}Basic grid
<article class="bars">
<div class="bar" data-percent="100"></div>
<div class="bar" data-percent="70"></div>
<!-- ... -->.bar {
height: attr(data-percent %); /* 70% */
}Sæt højden i %
<article class="bars">
<div class="bar" data-percent="100"></div>
<div class="bar" data-percent="70"></div>
<!-- ... -->.bar {
height: attr(data-percent %, 0%); /* 0% */
}Husk fallback!
<article class="bars">
<div class="bar" data-percent="100"></div>
<div class="bar"></div>
<!-- ... -->.bar {
background:
color-mix(#3980DD attr(data-percent %, 0%), #DAE9FC);
}Procent-værdien styrer baggrundsfarven
.bar {
--percent: attr(data-percent %, 0%);
background:
color-mix(#3980DD var(--percent), #DAE9FC);
height: var(--percent);
}Organiser med variabler
.bar {
&::after {
content: attr(data-percent) "%";
position: absolute;
top: -1lh;
inset-inline: 0;
justify-self: center;
}
}Vis procent-værdien
.bar {
&::after {
content: attr(data-percent) "%";
position: absolute;
top: -1lh;
inset-inline: 0;
justify-self: center;
}
}Vis procent-værdien
.bars {
@container (width < 400px) {
writing-mode: sideways-rl;
height: 100%;
}
}
.bar {
min-width: 40px;
}Gør den responsiv
div {
width: attr(data-length type(<length>));
&::after {
content: attr(data-length);
}
}writing-mode: sideways-lr | sideways-rl etc.
med flow-relative properties
med flow-relative properties
width
max-width
height
max-height
margin-left
margin-right
padding-top
top
inline-size
max-inline-size
block-size
max-block-size
margin-inline-start
margin-inline-end
padding-block-start
inset-block-start
med flow-relative properties
.bars {
@container (width < 400px) {
writing-mode: sideways-rl;
height: 100%;
}
}
.bar {
min-width: 40px;
}Gør den responsiv
.bars {
block-size: 300px; /* erstatter height */
@container (width < 400px) {
writing-mode: sideways-rl;
block-size: 100%; /* erstatter height */
}
}
.bar {
min-inline-size: 40px; /* erstatter min-width */
&::after {
inset-block-start: -1lh; /* erstatter top */
}
}Gør boksmodellen flow-relativ
.bars {
@container (width < calc((40px + 1rlh) * 8)) {
/* ... */
}
}
.bar {
margin-inline: .5rlh;
min-inline-size: 40px;
}Brug calc() i @container
bar width
.bars {
background:
repeating-linear-gradient(
to bottom,
gainsboro 0 1px,
transparent 0 25%
);
}Linjer med repeating-gradient
.bars {
background:
repeating-linear-gradient(
var(--angle, to bottom),
gainsboro 0 1px,
transparent 0 25%
);
}Fix linjer på små skærme
.bars {
background:
repeating-linear-gradient(
var(--angle, to bottom),
gainsboro 0 1px,
transparent 0 25%
);
@container (inline-size < 400px) {
--angle: to left;
}
}Fix linjer ved breakpointet
.bars {
background:
repeating-linear-gradient(
to bottom,
gainsboro 0 1px,
transparent 0 25%
);
}to bottom
0
1px
25%
(180deg)