Skip to content

Commit

Permalink
Feat: New Tutorial and Learnpaths
Browse files Browse the repository at this point in the history
  • Loading branch information
macx committed Oct 17, 2024
1 parent 08a6a6d commit 34d2dd9
Show file tree
Hide file tree
Showing 16 changed files with 297 additions and 68 deletions.
8 changes: 6 additions & 2 deletions src/components/Figure.astro
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,12 @@ if (imagePath !== undefined && !images[imagePath]) {
padding-block-end: var(--sp) 0;
}

> :is(img, .astro-code) + :where(.astro-code, .snippet) {
margin-block-start: var(--sp);
> :is(.astro-code) {
border: 0;

&:where(.astro-code, .snippet):not(:first-child) {
margin-block-start: var(--sp);
}
}
}
</style>
24 changes: 21 additions & 3 deletions src/components/Tags.astro
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
---
export interface Props {
tags: string[]
tags?: string[]
preSorted?: { name: string; number: number }[]
divider?: boolean
}
const { tags, divider } = Astro.props
const { tags, preSorted, divider } = Astro.props
const pathname = new URL(Astro.request.url).pathname
const currentPath = pathname.split('/').slice(3).join('').trim()
const sortedTags = tags.sort((a, b) =>
const sortedTags = tags?.sort((a, b) =>
a.localeCompare(b, 'de', { sensitivity: 'base' })
)
---
Expand All @@ -28,6 +29,23 @@ const sortedTags = tags.sort((a, b) =>
)
}

{
preSorted && preSorted.length > 0 && (
<ul class:list={['tags', { divider: divider === true }]}>
<li>Verwendete Tags:</li>
{preSorted.map((tag) =>
tag.number > 0 ? (
<li class:list={['tag', { current: currentPath === tag.name }]}>
<a href={`/tutorials/tags/${tag.name}`} class='tag'>
{tag.name}
</a>
</li>
) : null
)}
</ul>
)
}

<style lang='scss'>
.tags {
display: flex;
Expand Down
6 changes: 5 additions & 1 deletion src/content/learningpaths/layout.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@
"path": "/tutorials/lernpfade/layout",
"description": "steigst du tiefer in die Gestaltung von Websites ein.",
"order": 2,
"related": ["layouts-in-css", "logische-eigenschaften-in-css"]
"related": [
"absolute-und-relative-einheiten",
"logische-eigenschaften-in-css",
"layouts-in-css"
]
}
59 changes: 59 additions & 0 deletions src/content/snippets/relative-units/snippet-nested-boxes.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
import Snippet from '@components/Snippet.astro'
const { title } = Astro.props
---

<Snippet title={title}>
<div class='demo-nested-boxes'>
<div class='sn-element'>
<p>
<span class='code'>&#x3C;body&#x3E;</span><br />
<span class='t-small'>100&#8239;% des Viewports</span>
</p>

<div class='sn-element'>
<p>
<span class='code'>&#x3C;div class=&#x22;container&#x22;&#x3E;</span
><br />
<span class='t-small'>100&#8239;% vom Body</span>
</p>

<div class='flex'>
<div class='sn-element box50'>
<span class='t-small'>50&#8239;% vom Container</span>
</div>

<div class='sn-element box50'>
<p class='t-small'>50&#8239;% vom Container</p>

<div class='sn-element'>
<span class='t-small'>Wie lang bin ich?</span>
</div>
</div>
</div>
</div>
</div>
</div>

<style>
@scope (.demo-nested-boxes) {
:scope {
.flex {
display: flex;
justify-content: space-between;
gap: var(--sp);
}

.box50 {
flex: 1;
inline-size: 50%;
}

.light-text {
color: rgb(255 255 255 / 0.6);
}
}
}
</style>
</Snippet>
26 changes: 0 additions & 26 deletions src/content/snippets/typografie/snippet-relative-font-size.astro
Original file line number Diff line number Diff line change
@@ -1,31 +1,5 @@
---
import Snippet from '@components/Snippet.astro'
import { codeToHtml } from 'shiki'
const code = await codeToHtml('foo\bar', {
lang: 'js',
theme: 'vitesse-light',
transformers: [
{
code(node) {
this.addClassToHast(node, 'language-js')
},
line(node, line) {
node.properties['data-line'] = line
if ([1, 3, 4].includes(line)) this.addClassToHast(node, 'highlight')
},
span(node, line, col) {
node.properties['data-token'] = `token:${line}:${col}`
}
}
]
})
// const codeBlock = document.querySelector('#code')
// if (codeBlock) {
// codeBlock.innerHTML = code
// }
---

<Snippet title='Interaktive Demo'>
Expand Down
157 changes: 157 additions & 0 deletions src/content/tutorials/absolute-und-relative-einheiten.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
---
title: 'Längenmaße: Absolute und relative Einheiten in CSS'
description: 'Die Größe von Elementen kann in absoluten oder relativen Einheiten angegeben werden. Hier erfährst du, welche Einheiten es gibt und wann du welche verwenden solltest.'
isDraft: false
pubDate: 2024-10-17T15:40:00+00:00
author: david-maciejewski
cover:
path: '/src/images/tutorials/jahrmarkt-aepfel.png'
alt: 'Zwei Stundeniernde blicken fragend in Richtung Kamera.'
caption: 'Wie viele Äpfel kaufst du auf dem Markt? 12 oder 50 Prozent aus der Box?'
tags: ['css']
---

import Figure from '@components/Figure.astro'
import Table from '@components/Table.astro'

import SnippetNestedBoxes from '@snippets/relative-units/snippet-nested-boxes.astro'

## Unterschiede

Jede CSS-Deklaration enthält ein Paar aus Eigenschaft und Wert. Bei Längen- oder Größenangaben von HTML-Elementen werden numerische Werte verwendet, entweder als ganze Zahl oder als Dezimalzahl:

<Figure caption="`100px` ist ein absoluter, `1.5em` ist ein relativer Wert.">
```css
.box {
width: 512px;
font-size: 1.5em;
}
```
</Figure>

Wenn du dem Verkäufer auf dem Jahrmarkt bittest, dir 12 Äpfel zu verkaufen, dann ist das ein absoluter Wert. Wenn du dir hingegen die Hälfte der Äpfel aus der Kiste nimmst, dann ist das ein relativer Wert, abhängig von der Gesamtanzahl.

Auch in CSS gibt es absolute und relative Werte. Ein Beispiel: Der Bildschirm des Apple-Tablets iPad hat Pixelmaße von 1024x768. Möchtest du jetzt zwei Boxen nebeneinander darstellen und verwendest dabei fixe Werte wie `width: 512px`, dann wird dir das auf dem Smartphone um die Ohren fliegen. Zum einen sind die Dimensionen des Smartphones kleiner, zum anderen wird die Box auf dem iPad nicht nebeneinander dargestellt, weil der Platz nicht ausreicht.

Wenn du hingegen relative Einheiten wie Prozente (z.B. `width: 50%`) verwendest, dann passt sich die Box immer an die Größe des Elternelements[^1] an. Und das wiederum passt sich an die Größe des eigenen Elternelements an. Das geht so lang weiter bis zum obersten Element, dem Root-Elements[^2] `html`. Das ist im Übrigen 100&#8239;% des Viewport[^3] breit, also der Breite des Bildschirms. Das folende responsive Beispiel illustriert das:

<Figure caption="Was glaubst du? Wie lang ist die kleinste Box und woran orentiert sie sich?">
<SnippetNestedBoxes title="Demo" />
</Figure>

## Relative Einheiten

Die relativen Einheiten unterteilen sich in verschiedene Kategorien, abhängig von dem, woran du dich orientieren möchtest. Die gebräuchlichste Kategorie ist die der [relativen Schriftlängen](#relative-schriftlängen). Hierbei beziehen sich die Einheiten auf die Schriftgröße des Elternelements.

### Relative Schriftlängen

Neben der Angabe in Prozent, die du bereits schon kenngelernt hast, gibt es auch noch folgende Einheiten:

<Table mode="responsive">
| Einheit | Relativ zu |
|---------|--------------|
| `em` | Schriftgröße des Elternelements |
| `cap` | Höhe der Großbuchstaben |
| `ch` | Breite des Zeichens `0` |
| `ex` | Höhe des Buchstabens `x` |
| `lh` | Zeilenhöhe eines Elements |
</Table>

`em` ist dabei die gebräuchliste Einheit. Sie bezieht sich auf die Schriftgröße des Elternelements. `1em` entspricht 100&#8239;%, 150&#8239;% wären dann `1.5em`. Schauen wir uns exemplarisch das folgende Beispiel an.

In der Box soll der Fließtext 18 Pixel groß sein, also etwas größer als der Fließtext der anderen Elemente auf der Website. Die Überschrift soll 150&#8239;% der Schriftgröße unserer Box betragen.

<Figure caption="Die Schriftgrößer der Überschrift wird relativ zum Elternelement, also der Announcement-Box&nbsp;gesetzt.">
```html
<section class="announcement">
<h2>Bekanntmachung</h2>

Wir treffen uns Freitags in Haus E, Raum 08 (HIWEE08).
</section>
```
```css
.announcement { font-size: 18px; }
.announcement h2 { font-size: 1.5em; }
```
</Figure>

Die Überschrift entspräche umgerechnet `27px`. Die Formel dazu lautet: `18px * 1,5 = 27px`.

### Relativ zum Root-Element

Wenn du die 18 Pixel der Announcement-Box vom Beispiel oben ebenfalls relativ angeben möchtest, und das solltest du, dann kannst du das auch mit `em` tun. Der Haken an der Sache: Wenn du in die Announcement-Box eine weitere Announcement-Box einfügst, dann orientiert sich die zweite an der ersten Box. Desto mehr Boxen du ineinander verschachtelst, desto größer wird jeweils die Schrift. Während `1.5em` in der ersten Box 27 Pixel entsprechen, entsprechen `1.5em` in der zweiten Box 40.5 Pixel.

Klingt kompliziert und ist es auch. Besser wäre es, die Einheit `rem` zu verwenden. Das **r** in `rem` steht für **root** und bezieht sich dabei auf das Root-Element. Der Browser gibt vor, dass die Standardgröße für Fließtext **16 Pixel** groß ist, kann aber auch vom User in den Einstellungen verändert werden.

Noch einmal zusammengefasst:

em
: Die relative Einheit `em` bezieht sich auf die Schriftgröße des Elternelements. `1em` entsprechen 100&#8239;%, 150&#8239;% wären dann `1.5em`.

rem
: Die relative Einheit `rem` bezieht sich auf die Schriftgröße des `html`- oder `body`-Elements, das sind in der Regel `16px`. Das **r** in `rem` steht für **root**.

Der angepasste Code sieht dann so aus:

<Figure caption="Der Fließtext ist 18 Pixel, die Überschrift 27 Pixel groß.">
```css
.announcement { font-size: 1.125rem; }
.announcement h2 { font-size: 1.688rem; }
```
</Figure>

Hier einmal eine Gegenüberstellung unserer Announcement-Box, bei der wir (umgerechneet) 18 statt 16 Pixel verwenden:

<Table mode="scroll">
| Faktor | `em` entsprechen | `rem` entsprechen |
|------|------|------|
| 0.5 | `9px` | `8px` |
| 1 | `18px` | `16px` |
| 1.25 | `22.5px` | `20px` |
| 2 | `36px` | `32px` |
| 3.75 | `67.5px` | `60px` |
</Table>

Übrigens gibt auch von `cap`, `ch`, `ex` und `lh` eine Variante, die sich auf das Root-Element bezieht. Diese haben dann ein `r` vorangestellt, also `rch` statt `ch`.

> Unter [Assets](/assets#typografie) habe ich dir ein paar Links zu Tools interlegt, mit denen du die Größen berechnen kannst.
### Relativ zum Viewport

Der Vollständigkeit halber möchte ich noch die Einheiten erwähnen, die sich auf den Viewport und auf den Container beziehen. Das ist für dich am Anfang noch nicht sonderlich relevant, du wirst aber früher oder später in komplexeren Layouts darüber stolpern.

<Table mode="responsive">
| Einheit | Relativ zu |
|---------|--------------|
| `vh` | 1&#8239;% der Höhe des Viewports |
| `dvh` | 1&#8239;% der dynamischen[^4] Höhe des Viewports |
| `vw` | 1&#8239;% der Breite des Viewports |
| `dvw` | 1&#8239;% der dynamischen[^4] Breite des Viewports |
| `vmin` | 1&#8239;% des kleineren Wertes des Viewports (Breite oder Höhe) |
| `vmax` | 1&#8239;% des größeren Wertes des Viewports (Breite oder Höhe) |
</Table>

### Relativ zum Container

Längen, die sich auf einen Query-Container[^5] beziehen, sind:

<Table mode="responsive">
| Einheit | Relativ zu |
|---------|--------------|
| `cqb` | 1&#8239;% der Block-Größe des Query-Containers |
| `cqh` | 1&#8239;% der Höhe des Query-Containers |
| `cqi` | 1&#8239;% der Inline-Größe des Query-Containers |
| `cqw` | 1&#8239;% der Breite des Query-Containers |
| `cqmin` | 1&#8239;% des kleineren Wertes des Query-Containers (Breite oder Höhe) |
| `cqmax` | 1&#8239;% des größeren Wertes des Query-Containers (Breite oder Höhe) |
</Table>

## Aufgabe

Um die relative Einheiten besser zu verstehen, probiere doch einmal, die Announcement-Box mit den oberen CSS nachzubauen. Verwende erst `px` und `em` und teste das Ergebnis im Browser durch Verkleinern und Vergrößern des Fensters. Anschließend ersetze die Einheiten durch `rem` und beobachte den Unterschied.

[^1]: Das Elternelement ist das übergeordnete Element, in dem ein anderes Element eingebettet ist. Es kann auch als Container bezeichnet werden.
[^2]: Das Root-Element ist das oberste Element in der Hierarchie des DOM-Baums, also das `<html>`-Element.
[^3]: Der Viewport ist der sichtbare Bereich einer Website im Browserfenster. Er kann sich je nach Gerät und Bildschirmauflösung unterscheiden.
[^4]: Die dynamische Höhe und Breite des Viewports beziehen sich stets auf die aktuelle Größe des Viewports, also die Größe, die der Viewport gerade hat. Diese verändert sich zum Beispiel durch Scrollbalken oder die Adressleiste des Browsers.
[^5]: Container-Queries erlauben es, die Größe von Elementen an die Größe ihres Containers anzupassen und nicht an die des Viewports.
Loading

0 comments on commit 34d2dd9

Please sign in to comment.