Schriftarten
In Büchern und Zeitungen wird der Fließtext in der Regel mit Serifen-Schriften gedruckt. Die Serifen helfen, dass die Augen in der Zeile bleiben und das Lesen schneller gelingt und weniger ermüdend ist. Auf den ersten Computermonitoren mussten Buchstaben in einem Punktraster auf möglichst wenige Punkte beschränkt werden. Das lässt sich leichter mit Zeichen ohne Serifen umsetzen. Serifenlose Schriften werden auch bewusst dort eingesetzt, wo eine reduzierte Lesegeschwindigkeit erwünscht ist, z.B. in Schulbüchern.
Dass für die Auswahl der Standard-Schriftart des Fließtexts auf netzalben.de eine Schrift mit Serifen gewählt wurde, war auch die Folge zweier Entwicklungen:
- die Bildschirmauflösungen stiegen im Laufe der Zeit
- es wurden mittlerweile Schriftarten mit Serifen speziell für Bildschirme entwickelt
Letzteren fehlt unter den kostenlos verfügbaren Angeboten zwar das Filigrane, aber hinsichtlich der ermüdungsfreien Lesbarkeit können sie durchaus punkten. Für netzalben.de wurde die Lesbarkeit verschiedener Schriften auf kleinen und großen Bildschirmen untersucht. Bei der finalen Gegenüberstellung setzte sich Bitter gegen Lora und Source Serif durch.
In die nähere Auswahl für eine dazu passende serifenlose Schrift z.B. für Überschriften kamen nur die, die eine Verwechslung von klein-l und groß-I vermeiden. Die endgültige Wahl fiel auf Public Sans. Auf kleineren Bildschirmen wirkt sie größer und klarer. Diese Schriftart wurde übrigens von amerikanischen Steuerzahlern finanziert und darf allgemein genutzt werden. (im Gegensatz zu dem, was der deutsche Steuerzahler finanziert hat - grrr)
Eingebunden werden die Schriftarten als variable Fonts. Leider stand für die ausgewählten Schriften nur das ttf-Format zur Verfügung. Es ergibt sich dennoch ein deutlich reduziertes Transfer-Volumen, da nur noch jeweils eine Datei für die geraden und schrägen Schnitte benötigt wird.
/* latin-ext */
@font-face {
font-family: 'Public Sans';
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url(../fonts/Public_Sans/PublicSans-VariableFont_wght.ttf) format('opentype');
}
@font-face {
font-family: 'Public Sans';
font-style: italic;
font-weight: 100 900;
font-display: swap;
src: url(../fonts/Public_Sans/PublicSans-Italic-VariableFont_wght.ttf) format('opentype');
}
@font-face {
font-family: 'Bitter';
src:url(../fonts/Bitter/Bitter-VariableFont_wght.ttf) format('opentype');
font-style: normal;
font-weight: 100 900;
font-display: swap;
}
@font-face {
font-family: 'Bitter';
src: url(../fonts/Bitter/Bitter-Italic-VariableFont_wght.ttf) format('opentype');
font-style: italic;
font-weight: 100 900;
font-display: swap;
}
Text-Standards
Im standardmäßigen Stylesheet template.css werden weitere Konstanten definiert. Meistens gibt man diese Konstanten dem Pseudoelement :root mit, sie lassen sich aber auch an andere Elemente andocken.
:root {
--font-family-text: 'Bitter', serif;
--font-family-menu: 'Public Sans', sans-serif;
--font-family-heading: 'Public Sans', sans-serif;
--font-weight-heading: 300;
--font-size-smaller: .875em;
--font-size-small: .75em;
--font-line-height: 1.625;
--color--pre-hintergrund: #39424620;
--color--nav-hintergrund: #456;
--color--nav-transparent: #ebf5faab;
--color--nav: #fff;
--text-align: match-parent;
}
Die Standard-Einstellungen für den Fließtext werden dem Body-Element mitgegeben. So gibt es überall einen definierten Wert. Für spezielle Bereiche lassen sich die Werte später überschreiben. Die Schriftgröße wird mit der Bildschirmgröße geändert, besonders stark bei den Überschriften. Hintergrund ist die Überlegung, dass mit zunehmender Bildschirmgröße auch der Betrachtungsabstand steigt, wobei natürlich trotzdem mehr Information auf den Bildschirm passt.
body {
padding: 0;
margin: 0;
color: var(--color--text);
background-color: var(--color--hintergrund);
font-family: var(--font-family-text);
font-weight: 400;
font-size: calc(.97rem + .13vw);
}
Mit der Klasse .no-break kann manuell ein Bereich je nach Elementtyp vom Zeilen- oder Spaltenumbruch ausgeschlossen werden.
.no-break { break-inside: avoid; }
p, p + ul li {
margin-top: 0;
text-align: var(--text-align);
line-height: var(--font-line-height);
}
h1, h2, h3 {
font-family: var(--font-family-heading);
font-weight: var(--font-weight-heading);
}
h1 {
font-size: clamp(2rem, 1.4rem + 1.4vw, 3.625rem);
hyphens: none;
}
h2 {
font-size: clamp(1.5rem, 1rem + 1.3vw, 3.05rem);
hyphens: none;
}h3 {
font-size: clamp(1.25rem, .75rem + 1.125vw, 2.5rem);
margin-bottom: 1.5rem;
break-inside: avoid;
}
Die automatische Silbentrennung ist erst einmal auf den Hauptinhalt (s.u.) einer Seite ab Überschrift <h3> begrenzt.
Die folgenden Angaben sind hoffentlich weitgehend selbsterklärend. Ein geschütztes Leerzeichen benötigt in Joomla! scheinbar noch Hilfe vom Stylesheet.
/* Links in normaler Farbe */
a { color: var(--color--text); }
/* vorformatierter Text ( = Code) */
pre {
background-color: var(--color--pre-hintergrund);
padding: .25em .5em;
overflow-x: auto;
}
/* geschütztes Leerzeichen */
.mce-nbsp-wrap {
display: inline-block;
}
Bilder
„Bilder brauchen Größe!“ So titelte einmal eine Fotografie-Zeitschrift. Beim ersten Aufruf der Seite Turmbesteigung Aachener Dom hatten die Bilder die volle Breite angenommen. In Folge dessen konnte man die Bilder im Landschaftsformat vollständig betrachten, bei denen im Portraitformat musste gescrollt werden. In der Folge wurden die Standard-Größen für Bilder so definiert, dass der Bildschirm einerseits gut ausgenutzt wird, andererseits das Bild vollständig zu sehen ist.
/* Bilder */
img {
max-height: 100vh;
max-width: 100%;
height: auto;
width: auto;
}
figcaption {
font-size: var(--font-size-smaller);
text-align: center;
}
figure {
width: fit-content;
margin: 1em auto;
}
Joomla! gibt figure nur bei Bildern mit Beschriftung aus.
Sprung nach oben
Mit ein paar Stil-Angaben wird aus dem leeren Link hinter dem Hauptinhalt mit der Klasse top in index.php eine Schaltfläche, um an den Beginn der Seite zu springen.
/* zurück nach oben */
.top {
display: inline-block;
position: fixed;
bottom: 2em;
left: calc(100vw - 85px);
z-index: 1;
width:45px;
aspect-ratio:1;
background-color:var(--color--nav-transparent);
border-radius:22px;
}
.top::before {
content:"";
position:absolute;
inset:30%;
transform:translateY(20%) rotate(-45deg);
border-top:3px solid var(--color--nav-hintergrund);
border-right:3px solid var(--color--nav-hintergrund);
}
Globale Navigationsvorgaben
Für die Navigationselemente gibt es zunächst allgemeine Festlegungen.
/* Navigation allgemein (Menü, Breadcrumb, Footer) */
nav {
font-family: var(--font-family-menu);
}
nav ul {
margin: 0;
padding: 0;
}
nav li {
list-style-type: none;
display: inline;
}
nav a {
text-decoration: none;
color: var(--color--nav);
}
Der Kopf-Bereich
Das header-Element umschließt die Kopfzeile, in der sich links das Logo und das Breadcrumbmenü befindet und rechts das Hauptmenü. Die meisten Seiten werden ein Kopfbild haben, daher hat die Kopfzeile einen transparenten Hintergrund und einen z-index, der ermöglicht, dass das Bild durchscheinen kann.
/* Kopfzeile */
header {
background-color: var(--color--abdunkelung);
position: absolute;
top: 0;
width: 100%;
z-index: 5;
}
.kopfzeile {
border-bottom: var(--color--nav) solid .125em;
border-top: var(--color--nav) solid .125em;
font-family: var(--font-family-menu);
display: flex;
}
.kopfzeile li {
color: var(--color--nav);
}
Breadcrumbs
Das Logo hat zwar schon einen Link auf die Startseite, aber es ist auch konsequent, wenn Seiten, die direkt unter der Startseite hängen, diese als Breadcrumb anzeigen.
/* Kopfzeile linker Teil: Logo und Breadcrumbs */
.site-home {
display: flex;
align-items: center;
}
.site-logo {
padding: 0 1em;
height: 75px;
flex-shrink: 0;
}
.mod-breadcrumbs__wrapper {
max-width: calc(100vw - 11.5rem);
}
.mod-breadcrumbs {
padding: 0;
margin: 0;
}
.mod-breadcrumbs__item {
& span {
font-size: 1.125em;
}
&:not(:nth-of-type(2))::before {
content: " • ";
font-weight: 600;
}
}
Ansonsten wird im Stylesheet so auf die Ausgabe durch Joomla! reagiert, dass möglichst kein Override nötig wird. Der seit Ende 2023 in allen aktuellen Browser verfügbare Nesting-Selector (&) hätte auch schon weiter oben verwendet werden können, aber hier beim formulieren etwas komplexerer Regeln erweist er sich als sehr nützlich zur Kapselung, während oben bei den Menüpunkten die alte Schreibweise sehr verbreitet ist.
Hamburger - Icon
Das Hauptmenü wird rechtsbündig positioniert und mit den entsprechenden div-Elementen aus index.php der Burger gebildet.
/* Hauptmenü */
.mainmenu {
position: absolute;
right: 1em;
}
.burgericon {
width: 30px;
height: 30px;
float: right;
margin: 1em 1em 0 12em;
}
.burgericon div {
width: 90%;
margin: 7px 5%;
height: 3px;
background-color: var(--color--nav);
}
Der Burger ist so etwas wie die Beschriftung der Checkbox, die das Menü auf- oder zuklappt.
/* CheckBox */
#navigation {
opacity: 0;
}
#navigation ~ div ul {
display: none;
padding-left: 0;
}
#navigation ~ div ul>li {
display: block;
line-height: 2.5em;
border-bottom: solid gray 1px;
}
#navigation ~ div > ul > li:first-of-type { margin-top: 33px; }
#navigation ~ div ul > li:first-of-type { border-top: solid gray 1px; }
#navigation ~ div ul li:hover { background-color: var(--color--abdunkelung); }
#navigation ~ div ul li a { padding: 0 .75em; }
#navigation ~ div ul li>a:not(:has(+input)) { display: block; }
Hauptmenü
In der letzten Zeile bedeutet :has(+input) wenn es wahr wäre, dass sich dort ein Untermenü befindet. An dieser Stelle wird darauf nicht weiter eingegangen. Nur soweit: bei WordPress hat man eine Benutzeroberfläche um Menüs mit Untermenüs zusammenzustellen, die der Vorgehensweise bei Joomla! sinngemäß entspricht. Den Rest der Arbeit, also den korrekte Aufbau der HTML-Elemente für das Menü, lässt man sich von einem Plugin erledigen. Möglicherweise gibt es solche Erweiterungen auch für Joomla. Ich halte es nicht für ausgeschlossen, so etwas ausprobiert zu haben, ohne aber meine Designvorstellungen in vertretbarer Zeit umsetzen zu können.
Die Alternative zum Plugin besteht bei WordPress darin, dass man in der Oberfläche, in der man die Menüpunkte zusammenbaut, fehlende HTML-Schnipsel in die Eingabefelder einfügt. Das ist nicht immer trivial, aber es funktioniert.
Bei Joomla! muss man einen anderen Weg gehen. Hier ist es einfacher, die Ausgabe, so wie sie ist, an den Browser zu schicken und dort mit JavaScript die fehlenden Elemente im Dokumentenbaum zu ergänzen.
Hauptmenü geöffnet
Betätigt man den Burger, wird die CheckBox gecheckt und damit die folgende Liste, also das Menü, ausgeklappt. Gleichzeitig werden Menüs, die sich in dem Menü befinden, ausgeblendet.
/* Hauptmenü sichtbar */
#navigation:checked ~ div ul {
display: block;
background-color: dimgray;
& ul {display: none;}
}
Dann wird der Burger zu einem X.
#navigation:checked ~ label .burgericon {
margin-top: 1.5em;
& div:first-of-type { rotate: 45deg; }
& div:nth-child(2) { display: none; }
& div:last-child{
rotate: -45deg;
margin-top: -10px;
}
}
An dieser Stelle ist der Kopf der Seite, soweit er in der Datei index.php festgelegt wurde, fertig. Das Layout der Elemente, die die Komponente liefert, erfolgt weiter unten.
Der Footer
Im Footer werden bei netzalben.de nur die nötigsten Dinge untergebracht. Daher soll er möglichst einfach und unauffällig gestaltet werden.
footer {
color: var(--color--nav);
background-color: var(--color--abdunkelung);
font-family: var(--font-family-menu);
font-size: var(--font-size-smaller);
}
footer a {
text-decoration: none;
color: var(--color--nav);
}
footer div {
display: flex;
justify-content: space-between;
align-items: center;
}
footer li {
margin-left: 1em;
}
Der Haupt-Bereich
Automatische Silbentrennung
Im Haupt-Bereich der Seite sollen die Zeilen möglichst harmonisch aussehen. Da die deutsche Sprache sehr lange Worte kennt, wird hier generell die automatische Silbentrennung eingeschaltet.
/* main-Bereich */
main {
hyphens: auto;
position: relative;
z-index: 0;
min-height: 95vh;
}
Mindesthöhe
Die Mindesthöhe von 95% des Bildschirms bewirkt, dass bei Seiten mit wenig Inhalt, die Fußzeile dennoch am unteren Bildschirmrand erscheint. Durch den kleineren Wert von z-index schiebt sich die Komponente optisch unter den Header.
/* aus Komponente: */
/* Platz für Seitenkopf */
.page-header::before {
content: "";
position: relative;
display: block;
width: calc(100vw - 1.125rem);
min-height: 6em;
}
/* Seitenkopf ohne Bild*/
.page-header:not(:has(+figure)) {
margin-bottom: 1em;
}
Dazu wird oben auf der Seite ein Platz von mindestens 6 Einheiten reserviert.
Seitenkopf mit Bild
Zu einem Beitrag oder Kategorie kann auf der 2. Registerkarte ein Bild zugeordnet werden. Ist das erfolgt, gibt die Komponente das Bild mit einem umhüllendes Figurelement direkten nach dem .page-header aus.
/* Seitenkopf mit Bild*/
.page-header:has(+div>.headerbild),
.page-header:has(+figure) {
color: var(--color--nav);
text-align: center;
position: absolute;
z-index: 3;
&::before {
height: var(--cover-title-height);
}
}
/* Seitenkopf Überschrift */
.page-header:has(+div>.headerbild) h1,
.page-header:has(+figure) h1 {
border-bottom: var(--color--border) solid .125rem;
border-top: var(--color--border) solid .125rem;
background-color: var(--color--abdunkelung);
width: fit-content;
padding: .5em 1.5em;
margin: 0 auto;
}
/* figure nach .page-header hat die Klasse item-image */
.headerbild,
.item-image {
margin: 0;
position: relative;
z-index: 2;
}
.headerbild img,
.item-image img {
object-fit: cover;
height: 100vh;
width: 100vw;
}
Es gibt aber noch ein Problem: dieses Bild soll den gesamten Bildschirm ausfüllen. Das wird mit der Zeile object-fit: cover; ausgedrückt. In der Praxis wird das Bild ein anderes Format haben als der Bildschirm. Um die Vorgabe zu erfüllen, werden dann vom Browser je nachdem horizontal oder vertikal die Randelemente des Bildes symmetrisch beschnitten. Ohne eine weitere Vorgabe konzentriert sich der Blick in die Bildmitte. Leider hat Joomla! keine Bildverwaltung, die eine abweichende Position des optischen Schwerpunkt des Bildes speichern kann. WordPress hat sie übrigens auch nicht, aber dort kann man beim Einfügen eines Bildes dem Beitrag interaktiv die Werte mitgeben.
Optischer Schwerpunkt des Bildes
Wir müssen in diesem Fall das Beitragsbild in den Beitragsinhalt setzen und als solches kennzeichnen. Das geschieht dadurch, dass das Bild interaktiv an erster Stelle in den Beitrag eingefügt wird und dann im Quellcode-Editor ein umschließendes <div> der Klasse headerbild bekommt sowie zwischen dem öffnenden <img und dem Pfad zur Bildquelle noch die Styleangabe für die Objekt-Position erhält.
<div class="headerbild">
<img style="object-position: 61%;" src="/images/turmbesteigung-aachener-dom/Dom-Seitenansicht.jpg" width="2560" height="1220" loading="lazy" data-path="local-images:/turmbesteigung-aachener-dom/Dom-Seitenansicht.jpg">
</div>
Nur eine Angabe (hier 61%) bedeutet horizontal 61%, vertikal weiterhin 50%. Dies ist die einzige Stelle, an der Inline-Styling notwendig wird.
So, Ein- und Ausstieg aus der Seite sind jetzt OK!
Bleibt noch der eigentliche Inhalt. Zum Glück ist dessen Struktur bei der Turmbesteigung sehr einfach! Überschrift 2, Textabsätze und dann im Wechsel Bild, Text.
Seitenrahmen
Mit dem obigen Headerbild steht etwas im <main>-Bereich, das dort eigentlich nicht hin gehört. Um das weitere Vorgehen zu vereinfachen, fügt man noch davor über CMS Inhalt > Weiterlesen eine Trennlinie ein
<hr id="system-readmore">
und stellt bei der über System oder Dashboard erreichbaren Konfiguration unter Beiträge den Wert von Einleitungstext auf Verbergen.
Danach markiert man alles unter dem Headerbild und wählt dann im Menü des TinyMCE Format→ Formate→ Container→ section. Jetzt ist der gesamte Bereich unterhalb des Headerbildes in eine <section> eingeklammert, der man im HTML-Quelltext noch eine Id oder Klasse mitgeben sollte.
Beispiel für den Beginn des HTML-Quelltexts:
<p>Eindrücke von der Turmbesteigung des Aachener Doms</p>
<hr id="system-readmore">
<div class="headerbild"><img style="object-position: 61%;" src="/images/turmbesteigung-aachener-dom/Dom-Seitenansicht.jpg" width="2560" height="1220" loading="lazy" data-path="local-images:/turmbesteigung-aachener-dom/Dom-Seitenansicht.jpg"></div>
<section class="inhalt">
<h2>Bilder vom Handy</h2>
Container
Wir sind jetzt an der Stelle angekommen, an der bei WordPress der Gutenberg-Editor seine Stärken ausspielt. Es geht um Container-Elemente. Man kann es mit dem JCE, dem angeblich ultimativen Editor für Joomla! probieren, aber auch dort muss man noch in den HTML-Quelltext, um die CSS-Klassen zu ergänzen. Mich hat das nicht besonders überzeugt, so dass ich beim TinyMCE geblieben bin.
Auf einem Handy im Portrait-Format könnten wir dem Beitrag jetzt den letzten Feinschliff verpassen. Auf breiteren Bildschirmen wird aber die Darstellung nicht optimal sein:
- zu lange Textzeilen und
- viel weißer Platz rechts neben den Bildern
erscheinen besonders störend.
Textspalten
Obwohl sie als Stylesheet-Attribut verfügbar ist, hat sich eine Mehrspaltigkeit bei Webseiten noch nicht sehr verbreitet. Auf netzalben.de sollen lange Textzeilen vermieden und zur Verbesserung der Lesbarkeit auf breiten Bildschirmen in mehrere Spalten nebeneinander umgebrochen werden.
Die Klasse wird Spaltentext genannt. Das Vermeiden von Witwen und Schusterjungen unter 3 Zeilen funktioniert bei Firefox leider nicht.
.spaltentext {
text-align: justify;
column-width: max(min(40vw, 35em), 19.625em);
column-gap: var(--column--gap);
orphans:3;
widows:3;
margin-bottom: 1em;
&>h3:first-of-type {
margin-top: 0;
}
}
Bild mit Text
Zur Positionierung von Inhalten mit gleicher Breite nebeneinander dient die Klasse Spalten. Hierbei ist es unerheblich, ob innerhalb des Containers Texte oder Bilder stehen. Besteht in einer Spalte der Text aus mehreren Absätzen, sind diese mit <div> einzurahmen.
In der ersten WordPress-Version von netzalben.de wurde ein Block, der ein Bild mit Text gruppiert, verwendet. Das soll hier unter Berücksichtigung alle Formatierungswünsche nachgebildet werden. In beiden Fällen benötigt man Container-Elemente, die im HTML-Quelltext als <div>-Elemente der entsprechenden Klasse ergänzt werden müssen.
.spalten, .bildtext {
display: flex;
flex-direction: column;
margin: 0 auto 1em;
@media (orientation:landscape) {
flex-direction: row;
}
}
Es handelt sich um flex-Container, in denen der Inhalt auf schmalen Bildschirmen vertikal und auf breiten Bildschirmen horizontal erscheint. Dabei wechselt die Position des Bildes immer zwischen dem linken und rechten Rand. Bei der Zählung der even und odds bezieht sich der Browser auf die <div>-Elemente derselben Ebene, egal zu welcher Klasse sie gehören.
.spalten {
justify-content: center;
gap: 2em;
}
.inhalt-weit .spalten {
padding: 0 1.5rem;
}
.bildtext {
justify-content: space-between;
gap: 1em;
@media (orientation:landscape) {
justify-content: start;
gap: 2em;
&:nth-of-type(odd) {
flex-direction: row-reverse;
justify-content: end;
}
& div p {
width: 14em;
}
}
@media (orientation:portrait) {
text-align: justify;
}
}
Innerhalb des BildText-Containers werden um das Bild und um den Text jeweils noch <div>-Elemente benötigt,
- beim Bild, weil der TinyMCE sonst ein <p> setzen würde, was zu Abstandsproblemen führen kann
- beim Text, damit dieser auch aus mehreren Absätzen bestehen darf.
Das ursprüngliche <p> kann für Bilder vor der Bearbeitung des HTML-Quellcodes interaktiv nach Auswahl jedes Bildes über die Menüpunkte Format→Formate→Blöcke→Div geändert werden.
Der Container BildText funktioniert unabhängig davon, ob das Bild das erste oder zweite Element ist. Man sollte sich nach der natürlichen Reihenfolge auf einem schmalen Bildschirm richten. Dort erscheinen die Elemente untereinander.
