Crafting UI

Datavisualisering (CSS og SVG)

Datavisualisering

Datavisualisering

Det handler ikke kun om at vise data men om at designe den måde, data forstås på.

  • gør kompleks data læsbar, sammenlignelig og handlingsbar
  • fremhæver mønstre, relationer og afvigelser
  • fører (måske) til øget engagement

Fra temaopgaven

Procentcirkler

Datavisualisering

CSS

SVG

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)';
}

Pseudo-elementer

::before, ::after

a[href^="http"]::after {
  content: '(opens in new tab)';
}

Pseudo-elementer

::before, ::after

Pseudo-elementer

::before, ::after

a[href^="http"]::after {
  content: '(opens in new tab)';
}

Øvelse

nav.innerHTML += `<a href=${c.link}>${c.name}</a>` + " / ";

Pseudo-elementer

Øvelse

Pseudo-elementer

Øvelse

nav.innerHTML += `<a href=${c.link}>${c.name}</a>` + " / ";

Pseudo-elementer

Øvelse

li + li::before {
  content: '/';
}

Pseudo-elementer

Øvelse

li + li::before {
  content: '/';
}

Pseudo-elementer

li:has(a)::after {
  content: '/';
}
li:has(+ li)::after {
  content: '/';
}
li:not(:last-child)::after {
  content: '/';
}
:not(:first-child)::before {
  content: '/';
}

Pseudo-elementer

Fra Temaopgaven

Pseudo-elementer

Øvelse

Pseudo-elementer

Øvelse

Pseudo-elementer

Tegn med gradienter

Koniske, lineære, radiale

Tegn med gradienter

Koniske, lineære, radiale

Conic-gradient()

Procentcirkel (doughnut)

Offset-path

Offset-path

.parent {
  .child {
    offset-path: border-box;
  }
}

Offset-path

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}%`

attr()

div {
  width: attr(data-length type(<length>));
  &::after {
    content: attr(data-length);
  }
}

attr(data-number type(<number>), 0)

<div data-length="5rem"></div>

attr()

Hent og brug værdier fra attributter

div {
  width: attr(data-length type(<length>));
  &::after {
    content: attr(data-length);
  }
}

attr()

Units vs. Types

attr()

Types of type()

<angle>

<color>

<custom-ident>

<image>

<integer>

<length>

<length-percentage>

<number>

<percentage>

<time>

attr()

og calc()

div {
  height: attr(data-percent %), 0%);
}

Lad os bygge en
responsiv Bar Chart

.bars {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  height: 300px;
}

Step 1: Orientering

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% */
}

Step 2: attr()

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% */
}

Step 2: attr()

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);
}

Step 3: color-mix()

Procent-værdien styrer baggrundsfarven

.bar {
  --percent: attr(data-percent %, 0%);
  background:
    color-mix(#3980DD var(--percent), #DAE9FC);
  height: var(--percent);
}

Step 4: Housekeeping

Organiser med variabler

.bar {
  &::after {
    content: attr(data-percent) "%";
    
    position: absolute;
    top: -1lh;
    inset-inline: 0;
    justify-self: center;
  }
}

Step 5: pseudo-element

Vis procent-værdien

.bar {
  &::after {
    content: attr(data-percent) "%";
    
    position: absolute;
    top: -1lh;
    inset-inline: 0;
    justify-self: center;
  }
}

Step 5: pseudo-element

Vis procent-værdien

.bars {
  @container (width < 400px) {
    writing-mode: sideways-rl;
    height: 100%;
  }
}

.bar {
  min-width: 40px;
}

Step 6: writing-mode

Gør den responsiv

writing-mode

div {
  width: attr(data-length type(<length>));
  &::after {
    content: attr(data-length);
  }
}

writing-mode: sideways-lr | sideways-rl etc.

writing-mode

med flow-relative properties

writing-mode

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

writing-mode

med flow-relative properties

.bars {
  @container (width < 400px) {
    writing-mode: sideways-rl;
    height: 100%;
  }
}

.bar {
  min-width: 40px;
}

Step 6: writing-mode

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 */
  }
}

Step 7: Logical props

Gør boksmodellen flow-relativ

.bars {
  @container (width < calc((40px + 1rlh) * 8)) {
    /* ... */
  }
}

.bar {
  margin-inline: .5rlh;
  min-inline-size: 40px;
}

Tip

Brug calc() i @container

bar width

.bars {
  background:
    repeating-linear-gradient(
      to bottom,
      gainsboro 0 1px,
      transparent 0 25%
    );
}

Step 8: Gitterlinjer

Linjer med repeating-gradient

.bars {
  background:
    repeating-linear-gradient(
      var(--angle, to bottom),
      gainsboro 0 1px,
      transparent 0 25%
    );
}

Step 8: Gitterlinjer

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;
  }
}

Step 8: Gitterlinjer

Fix linjer ved breakpointet

Hvordan virker det?

.bars {
  background:
    repeating-linear-gradient(
      to bottom,
      gainsboro 0 1px,
      transparent 0 25%
    );
}

to bottom

0

1px

25%

(180deg)

Crafting UI: Datavisualisering

By Dannie Vinther

Crafting UI: Datavisualisering

Crafting UI – Datavisualisering

  • 74