CSS/Tutorials/Einstieg/vom Entwurf zum Layout

Aus SELFHTML-Wiki
< CSS‎ | Tutorials‎ | Einstieg
Wechseln zu: Navigation, Suche
Dieses Tutorial erklärt, wie Sie Webseiten so gestalten, dass sie flexibel und responsiv auf jedem Gerät passend dargestellt werden.

Dabei wird Wert darauf gelegt, dass CSS-Festlegungen nach den Regeln der "best practice" so organisiert und notiert werden, dass sie von Ihnen und anderen leichter verstanden und dann später auch aktualisiert werden können.

Beachten Sie:
Nicht ohne Grund gibt es die Schlagworte „Content is King!“ und „Form follows function“.
Eine Webseite können Sie erst gestalten, wenn Sie Inhalte und Struktur haben. Ein wireframe ist eine Hilfe, aber kein vollwertiger Ersatz!

Vom Regelsatz zum responsiven Layout

In den ersten Kapiteln wurde CSS eher theoretisch beleuchtet- nun wollen wir einem Entwurf aus dem Forum [1] mit CSS ein modernes responsives Layout geben.

wireframe
Wireframe - konzeptioneller Entwurf ohne Gestaltung und Funktion

Die Farbpalette richtet sich an einer lila Grundfarbe aus, die durch die Komplementärfarben orange und grün als Akzente ergänzt werden.

wireframe
Farbpalette - Mockup der Startseite

Das HTML-Markup unserer Webseite besteht nun aus dem (unsichtbaren) Grundgerüst und semantisch passenden Seitenstrukturierungs-Elementen.

Wichtig: Der Querbalken des Kreuzes ist nur Dekoration, findet sich im HTML-Markup also nicht wieder!

Mobile first

Webseiten sollen responsiv sein und sich flexibel an den verfügbaren Platz anpassen. Dabei müssen die Inhalte nicht gleich aussehen, sondern gut lesbar sein - welcher Nutzer vergleicht eine Seite gleichzeitig auf mehreren Geräten?

Deshalb werden in einer ersten Version nur die Farben und Schriftarten festgelegt.

1. Schritt: Farben, Schriftarten und Innenabstände ansehen …
:root {
	--accent1: #70369b;
	--accentmedium1: #7f4ba5;
	--accentlighter1: #df84de;	
	--accent2: #e87110;
	--accentlighter2: orange;
	--accent3: #1ee7b9;
	--backgroundColor: linen;
	--textColor: #333;
	--navColor: #fff;
	
	--navWidth: 12em;
	--mainWidth: min(48em, calc(100% - var(--navWidth)));
	--headerLineHeight: 3em;
}

body {
	background: var(--backgroundColor);
	color:      var(--textColor);
	font-family: Avenir, Arial, sans-serif; 
	min-height: 100vh;
	margin: 0;
	padding: 0;
}
header {
	padding: 2em;
}
nav {
    background: linear-gradient(90deg, var(--accentlighter1), var(--accentmedium1)) ;
    color: var(--navColor);
    padding: 1em;
}
...

Dieses CSS besteht aus zwei Abschnitten:

  1. Die in der Entwurfsphase ausgewählte Farbpalette wird mit custom properties für den root-Selektor festgelegt.
    • custom properties - oft auch als CSS-Variablen bezeichnet, sind selbstdeklarierte Eigenschaften, die man am vorangestellten --… erkennt. Diesem Eigenschaftsnamen wird dann ein Wert zugewiesen:
      • die Farbwerte der oben erwähnten Farbpalette
      • --navWidth, --mainWidth und --headerLineHeight, die zentral Abstände festlegen
  2. body und einige Seitenstrukturierungselemente erhalten über den jeweiligen Typselektor
    • Text- und Hintergrundfarbe - Dabei werden die oben deklarierten custom properties über die var()-Funktion wieder aufgerufen.
    • sowie unterschiedliche Innenabstände.
  3. Auf Breiten- und Höhenangaben wird verzichtet!
    • Alle Elemente werden in der vollen Breite untereinander angeordnet.
    • Die Höhe richtet sich nach dem vorhandenen Inhalt.

Dieser Ansatz erleichtert auch das (spätere) Anlegen eines Print-Stylesheets für eine Druckausgabe.

Breakpoints: Inhalt über Design

Eine Stärke von CSS liegt darin, die Darstellung eines Dokuments mit Hilfe von Medienabfragen (media queries) je nach Ausgabemedium verschieden festlegen zu können. So können Sie im Druckbereich von der normalen Bildschirmansicht abweichende Formatierungen festlegen.

Ihre volle Stärke entfalten Media Queries mit Hilfe von Medienmerkmalen, mit denen Sie z.B. unterschiedliche Viewport-Breiten berücksichtigen können.

Für welche Geräte muss ich wann Breakpoints setzen?

So oder ähnlich lauten viele Fragen im Forum. Die Antwort darauf lautet: "Gar nicht!"

Viewportauflösungen heutiger Geräte

Derzeit aktuelle Geräteauflösungen können morgen schon überholt sein.

  • Richten Sie lieber die Breakpoints am Inhalt aus:[2]
  • Überlegen Sie, ab wann dieser bei einer bestimmten Viewportbreite nicht mehr gut aussieht.
    • Bei Text ist es eigentlich egal, höchstens ein max-width: 60em;, damit die Zeilen nicht zu lang werden.
    • Bei Grafiken und bestimmten Seitenelementen sollten Sie flexible, prozentuale Breiten verwenden, damit Bilder
      • auf schmalen Bildschirmen 100% breit dargestellt werden
      • auf Tablets in landscape-Modus nebeneinander oder
      • auf breiten Bildschirmen drei oder vier nebeneinander dargestellt werden.


Eric Eggert (und wir) empfehlen:
Setzen Sie Breakpoints nicht nach vermeintlichen Gerätegrößen!
2.Schritt: für breitere Viewports Elemente nebeneinander
body { 
    display: grid; 
    gap: 1em;
}
@media (min-width: 30em) {
  body { 
    grid-template:	"nav head" min-content
                    "nav main" auto
                    "nav foot" min-content /
                    12em 1fr;
    } 
}

Im Grundzustand Mobile First! werden alle Seitenelemente untereinander angeordnet. Bei einer Viewportbreite von mindestens 30em soll die Navigation links angeordnet werden. Dies erreichen wir, indem wir grid-template-columns eine ASCII-Map unseres Seitenaufbaus geben. Rechts stehen die jeweiligen Höhenangaben, die nicht in festen Pixelwerten sondern mit min-content angegeben werden. So wird sichergestellt, dass alle Inhalte immer angezeigt werden!

Die Breitenangaben unten sind mit 12em Breite für die Navigation vorher abgemessen, der Inhaltsbereich verteilt sich auf den Rest.

In unserer Zeichnung sollte sich die Navigation aber kreuzartig über die Seite zu erstrecken. Ein solcher Querbalken kann eingefügt werden - da er nur zur Dekoration dient, aber nicht im HTML, sondern nur im CSS:

3.Schritt: für breitere Viewports Elemente nebeneinander ansehen …
:root {
	--navWidth: 12em;
	--mainWidth: min(48em, calc(100% - var(--navWidth)));
	--headerLineHeight: 3em;
}

@media (min-width: 30em) {
  body { 
    display: grid;  
    grid-template:  ". nav head ." min-content
				    ". nav rule ." var(--headerLineHeight)
				    ". nav main ." auto
				    ". nav foot ." min-content /
				1fr var(--navWidth) var(--mainWidth) 1fr;
    } 
    body::before {
        content: '';
        grid-row: rule;
		grid-column: 1 / 1;
        background: linear-gradient(to right, var(--accent1), var(--accentlighter1));
    }
    body::after {
        content: '';
        grid-row: rule;
		grid-column: rule-start / -1;
        background-image: linear-gradient(to right, var(--accentmedium1), var(--accent1));
    }
}
@media (min-width: 40em) {
  header {
    display: grid;
    grid-template-columns: 1fr 2fr;
	padding: 1em 1em 1em 2em;
    gap: 2em;
	justify-items: center;
  }
}

Dieses Beispiel folgt dem Grundsatz "Mobile first!" und enthält nach den oben beschriebenen Farbfestlegungen zwei media queries:

  • Auf kleinen Viewports nehmen alle Blockelemente ohne weitere Festlegungen die volle Breite ein.
  • Ab einer Mindestbreite von 30em trifft die Medienabfrage @media (min-width: 30em) zu und es wird ein Raster angelegt:
    • Mit grid-template werden innerhalb der Anführungszeichen 2x4 Rasterbereiche festgelegt, denen als zusätzlicher Wert die Höhe beigefügt wird.
      • Das nav-Element nimmt alle (drei) Zellen der ersten Spalte ein; header, main und footer kommen in die rechte Spalte
      • Allerdings ist das Template vierspaltig: 1fr var(--navWidth) var(--mainWidth) 1fr;
        links und rechts der beiden Inhaltsspalten werden jeweils 1fr notiert, um den Inhaltsbereich zu zentrieren.
    • Die zweite Reihe ". nav rule ." var(--headerLineHeight) legt nun einen Rasterbereich rule (engl. für Maß) fest. Dieser findet sich nicht im HTML.
      • Im Regelsatz body::before{...} wird nun ein Pseudoelement erzeugt, dass diesen rule-Bereich mit der Dekorationsgrafik füllt. Anstelle einer Rastergrafik im jpeg-Format wird der Verlauf allein mit CSS erzeugt.
  • Ab 40em Breite ist die zweite Spalte so breit, dass Logo und Teaser nebeneinander stehen können. Deshalb erhält der header ein weiteres Grid, das seine Kindelemente img und span in Rasterzellen verwandelt.
Hauptartikel: CSS/Tutorials/Grid/benannte Linien und Rasterbereiche

auf Benutzerwünsche eingehen

Mit Media Queries können Sie nicht nur Geräteabmessungen, sondern auch Benutzereinstellungen abfragen und ihr Layout entsprechend anpassen. So wünschen viele Benutzer einen Dark Mode, der sich mit wenigen Zeilen CSS realisieren lässt:

4.Schritt: Dark Mode ansehen …
@media (prefers-color-scheme: dark) {
  /* dunkles Farbschema für die Nacht */
  body {
    --textColor: white;
    --backgroundColor: black;
  }

  a {
    color: skyblue;
  }
  h1,h2,h3 {
    color: var(--accentlighter1);
  } 
}

Mit prefers-color-scheme wird abgefragt, ob ein dunkles Schema gewünscht wird. Falls dies der Fall ist, werden die entsprechenden custom properties neu gesetzt.

Screenshot: HTML-Dokument mit CSS-Stylesheet
HTML-Dokument mit CSS-Stylesheet für Light und Dark Mode

Wie oben bereits erwähnt, kam die Design-Idee aus dem SELF-Forum. Dieses Beispiel findet sich weiter ausgebaut unter unseren fertigen Layouts:



Mit einigen wenigen CSS-Eigenschaften haben wir nun bereits ein individuelles, unverwechselbares Erscheinungsbild. Wie im letzten Kapitel besprochen verzichten wir auf eine „Normalisierung“ und vertrauen dem Browser-Stylesheet.

„Modernes CSS ist eben nicht mal alle Abstände auf 0 zu setzen und Links in Textfarbe ohne Unterstreichung zu formatieren!“

Nun zum …

Fine-Tuning

Überschriften mit anderen Schriftarten

Eines der besten Mittel einer Webseite ihren „eigenen“ Look zu geben ist die Verwendung einer speziellen Schriftart.

andere Schrift für Überschriften ansehen …
<link href="https://fonts.googleapis.com/css2?family=Gloria+Hallelujah&display=swap" rel="stylesheet">
Über das link-Element wird die gewünschte Schriftart eingebunden.


Alternativ kann man das auch zentral im Stylesheet mit einer @import-Regel erledigen:
@import url('https://fonts.googleapis.com/css2?family=Gloria+Hallelujah&display=swap');

h1,h2,h3 {
    color: var(--accent1);
    font-family: 'Gloria Hallelujah', cursive;
    text-align:center;	
}

// Besser: fonts selbst hosten:

@font-face {
    font-family: 'Cantarell';
    font-style: normal;
    font-weight: 700;
    src: local('Cantarell Bold'), local('Cantarell-Bold'), url(../font/Cantarell-Bold.ttf) format('truetype');
}

Allen Überschriften von h1 bis h3 wird mit font-family die Schriftart Gloria Hallelujah zugewiesen. Falls die nicht geladen werden kann, wird als Fallback die Schriftfamilie cursive angegeben.

Über @font-face können Sie die URL des selbst gehosteten Fonts angegeben.

Beachten Sie: So verlockend es scheint, Schriften mit einer Zeile Code von einem CDN zu laden, sollten Sie Fonts immer selbst hosten.

Serife.svg

Dabei muss aber stets die Lesbarkeit der Texte im Auge behalten werden. Viele Zierschriften mit Serifen benötigen eine gewisse Schriftgröße, um sie zufriedenstellend anzuzeigen. Deshalb empfiehlt man oft, für Fließtext die Standardschrift des Browsers zu nehmen und die eigene Schriftart nur für Überschriften und wichtige Zitate.

Hauptartikel: Typografie

Größen und Abstände

Wie oben bereits erwähnt, ist es empfehlenswert, sich generell auf die Grundeinstellungen des Browser-Stylesheet zu verlassen. Allerdings müssen Sie bei besonderen Schriften darauf achten, dass Unterlängen nicht in den nachfolgenden (Text)-Inhalt ragen.

zu großé Unterlänge verdeckt nachfolgenden Text

Hier können Sie mit line-height und margin-bottom entgegensteuern.

h1, h2, h3 {
  font-size:     24px;
  line-height:   36px;
  margin-bottom: 10px;
}

Relative Einheiten wie %, em oder rem sind für ein responsives Design besser geeignet. Hauptsächlich deshalb, weil sie im Stande sind, mit unterschiedlichen Bildschirmgrößen zu skalieren.

em Relativ zur font-size des Elements selbst (Dezimalwert)
rem Relativ zur Schrifthöhe (font-size) des html-Elements (Dezimalwert)
% Relativ zu einer Längenangabe Elternelement.
vw Relativ zur Breite des Viewports (Prozentwert)
vh Relativ zur Höhe des Viewports (Prozentwert)

Jeder Browser legt eine Defaultgröße für Text fest, zumeist font-size: 16px. Die Einheit rem verwendet diesen Wert als Rechenbasis. Wenn ein Anwender die Standardtextgröße in seinem Browser verändert, skaliert alles auf der Seite passend zur Basisgröße. Maße, die Sie in rem angeben, werden mit dieser Größe multipliziert. Zum Beispiel:

.8rem = 12.8px  (0,8 * 16)
1rem  = 16px    (1 * 16)
2rem  = 32px    (2 * 16)

Was ist, wenn Sie oder der Anwender die Defaultschriftgröße ändern? Wie schon gesagt, dies sind relative Einheiten und die endgültigen Größenwerte werden dann aus der neuen Basisgröße ermittelt. Das ist in Media Queries nützlich; man muss nur die Schriftgröße verändern und die ganze Seite skaliert dementsprechend hoch oder herunter.

rem-Werte bei 10px Basisschriftgröße
html {
  font-size: 10px;
}
 .8rem =  8px (0,8 * 10)
  1rem = 10px (1   * 10)
  2rem = 20px (2   * 10)

Mit Prozentangaben lässt sich der Wert einer Eigenschaft basierend auf dem Wert einer Elterneigenschaft festlegen. Welcher das ist, ist nicht immer ganz logisch, und muss im Zweifelsfall bei der festzulegenden Eigenschaft nachgeschlagen werden.

Beachten Sie: Alle genannten Einheiten, außer Prozent, sind Längeneinheiten und lassen sich überall dort verwenden, wo eine CSS-Eigenschaft eine Länge erwartet. Die Angabe eines Prozentwertes an Stelle einer Länge ist an vielen Stellen zulässig, aber nicht überall. Beispielsweise ist die Angabe einer Randdicke (border-width) nicht in Prozent möglich.
Prozentangaben
html {
  font-size: 16px;
}
p {
   font-size: 200%;    /* Bezieht sich auf die font-size des Elternelements */
   width: 50%;         /* Bezieht sich auf die Breite des Elternelements */
   padding-top: 5%;    /* Bezieht sich ebenfalls auf die Breite des Elternelements! */
}

Diese CSS-Regel stellt p-Elemente mit einer Schrift dar, die doppelt so groß wie die Schrift im Elternelement ist. Wenn sonst nirgends Schriften festgelegt wurden, wären das im Beispiel 32px. Die Breite der p-Elemente wäre die Hälfte der Breite des Elternelements (z. B. des body).

Achtung!

padding-Angaben beziehen sich immer auf die Breite des Elternelements. Auch padding-top!


Und was ist der Unterschied zwischen den Einheiten rem und em?

Er besteht darin, was die Einheit als Basiselement verwendet. rem berechet Werte basierend auf der font-size des <html>-Elements, während ein Element, das em-Werte spezifiziert, seine eigene font-size verwendet. Ein Sonderfall ist dabei die Angabe der eigenen font-size in em, dieser Wert bezieht sich auf vom Elternelement geerbte font-size. Wenn sich die font-size des Elternelements von der im <html> Element unterscheidet, ermitteln rem und em unterschiedliche Werte. Damit erhalten wir eine feinere Kontrolle darüber, wie sich unsere Elemente in unterschiedlichen responsiven Kontexten verhalten.

vh ist eine Abkürzung für viewport height. Der Viewport ist der Teil des Browserfensters, der die Webseite darstellt. 100vh ist die vollständige Höhe des darstellbaren Bereichs (also des Browserfensters abzüglich Rändern, Titelleiste, Adresszeile, Lesezeichenzeile und ggf. weiterer Gimmicks). Dementsprechend ist 100vw (viewport width) die vollständige Breite dieses Bereichs.

Anmerkung des Übersetzers: Leider ist die CSS-Spezifikation hier nicht ganz exakt und es gibt Unklarheiten, wie Scrollbars zu behandeln sind und was passiert, wenn ein Mobilgerät-Browser beim Scrollen die Adresszeile wegblendet oder eine Tastatur einblendet. Ursprünglich hat sich vh an solche Ein- oder Ausblendungen angepasst, mit unangenehmen Folgen für die Darstellung der Seite. Deswegen wurde das in Safari für iOS und Chrome für Android geändert, vh bleibt dort nun konstant. In Firefox für Android ist das (Stand September 2020) ein sechs Jahre altes, offenes Ticket.

Minimum- und Maximum-Werte in CSS setzen

Die Vergleichsfunktionen min() und max() dienen dazu, den kleinsten beziehungsweise größten Wert aus einer Liste von Werten auszuwählen. Damit kann man erreichen, dass der berechnete Wert für eine Eigenschaft einen bestimmten Wert nicht überschreitet oder unterschreitet. Es ist allerdings nicht ganz intuitiv: um für eine Eigenschaft einen Maximalwert festzulegen, muss man die min() Funktion verwenden – weil ja in dem Moment, wo der berechnete Wert das gewünschte Maximum überschreitet, dieses Maximum der kleinere der beiden Werte ist.

Festlegen einer maximalen Breite für einresponsives Bild ansehen …
  img {
    width: min(100%, 400px);
  }

Die Grafik ist responsiv und nimmt 100% der Containerbreite ein, bis zu einem Maximalwert von 400px. Um dies zu veranschaulichen wird die Breite des body-Element durch eine CSS-Animation verändert.

clamp()

Es kommt auch vor, dass man eine Unter- und eine Obergrenze festlegen möchte. Dazu kann man min und max kombinieren, z. B. so: width: max(300px, min(50%, 800px) );. Die Breite des Elements wird auf 50% des Elternelements festgelegt, aber mindestens 300px und nicht mehr als 800px. Um eine solche Angabe lesbarer zu gestalten, gibt es die Funktion clamp():

Festlegen eines Wertebereichs für eine Eigenschaft
.box {
   width: clamp(400px, 50%, 800px);   /* 50% Breite, mindestens 400px und höchstens 800px*/
}
Zitat mit flexibler Schriftgröße ansehen …
blockquote {
	font: 1.2em/1.4 Georgia, serif;
	font-size: clamp(1.2em, 4vw, 1.8em);
	max-width: 28em;
}


Weblinks


Quellen

  1. SELF-Forum: Die Media-Queries bringen mich zum Heulen... von Michael S. 27.02.2022
  2. learn-the-web: Screen sizes cheat sheet (Kategorien von Bildschirmgrößen, mit passenden em-Angaben)