Automatische Korrektur von Einrückungen im Layout basierend auf typografischen Stilen und Textmetriken

Die Organisation der Einrückung während des Layouts und der Komposition der Elemente auf der Seite erfordert einige Fähigkeiten, um die richtigen Kombinationen und das gewünschte Ergebnis sicherzustellen.

Und wenn im Designlayout die angeforderten Einrückungen angezeigt werden, ohne die Zeilenhöhe und die leeren Schriftwiedergabebereiche (Schultern, Diakritika, absteigende Höhe) zu berücksichtigen? Wie kann man das Layout so nah wie möglich am Layout effizient und ohne lange manuelle Nachzählungen gestalten? Mit dem führenden und vertikalen Rhythmus können Sie die Abstände zwischen den Elementen vereinheitlichen, das Problem der Entfernungskompensation jedoch nicht lösen, indem Sie die Textmetriken der verwendeten Schriftarten berücksichtigen.

Bei der Entwicklung von Anwendungen für Luxuskunden wird besonderes Augenmerk auf die Genauigkeit der Implementierung der Schnittstelle gelegt, bei der jedes Pixel unter Kontrolle ist.

In diesem Artikel betrachten wir einen Ansatz zur Optimierung der Routinearbeit um Einrückungen - automatisierte Einrückungsanpassung basierend auf der Zeilenhöhe der Zielelemente und Textmetriken der Schriftarten, die in der Phase vor oder nach der Kompilierung von Stilen verwendet werden.

Designspezifikationsanforderung


Daher muss der Abstand zwischen den Elementen, die den Text enthalten, von der Grundlinie eines Elements bis zum oberen Rand des Großbuchstabens (Großbuchstaben) des nächsten Elements einen bestimmten Wert haben (z. B. 24 Pixel), mit Ausnahme des Bereichs zum Zeichnen von Diakritika und Schultern.

Design-Erwartungen

Wenn Sie diesen Wert in Deklarationen wie Auffüllen oder Rand verwenden, wird zwischen den Elementen ein Einrückungsbereich gebildet, der Folgendes enthält:

  1. Der direkt angegebene Einrückungswert (24px) zwischen den Elementen.
  2. (Über dem Einzug) Der Abstand zwischen der Grundlinie des Texts (Grundlinie) und dem unteren Rand (untere Peillinie) des Schriftbegrenzungsrahmens (Schriftbegrenzungsrahmen, B-Feld, B-Feld) ist die Höhe des unteren Versatzes (Abstiegshöhe).
  3. (Über dem Einzug) Der Abstand zwischen dem unteren Rand des Schriftbegrenzungsrahmens und dem unteren Rand der Zeilenhöhe des Elements (z. B. 4 Pixel bei Angabe von 16 Pixel / 1,5).
  4. (Eingerückt) Der Abstand zwischen dem oberen Rand der Zeilenhöhe und dem oberen Rand des Schriftbegrenzungsrahmens. Zum Beispiel 4px bei Angabe von 16px / 1.5).
  5. (Eingedrückt) Der Abstand zwischen der oberen Peilungslinie des Schriftbegrenzungsrahmens und der Linie durch den oberen Rand des Großbuchstabens (Kappenlinie), der das diakritische Zeichen und die Schultern enthält.

(Schriftmessungen)

Beispiel


Betrachten Sie als Beispiel die Implementierung eines Banners mit Text:


Typografische Stile, die auf ein Kontingentprojekt angewendet werden:

/*
Typography styles
*/
.type-h2 {
  font-family: Arial;
  font-size: 35px;
  line-height: 40px;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 2px;
  html[lang^="de"] & {
    font-family: 'Karla Bold';
    font-size: 35px;
    line-height: 40px;
  }
}
.type-p1 {
  font-family: Arial;
  font-size: 16px;
  line-height: 22px;
  font-weight: normal;
  letter-spacing: 0;
  html[lang^="de"] & {
    font-family: 'Karla Regular';
    font-size: 16px;
    line-height: 22px;
  }
}
@media only screen and (min-width: 480px) and (max-width: 767px) {
  .type-h2 {
    font-family: Arial;
    font-size: 50px;
    line-height: 55px;
    html[lang^="de"] & {
      font-family: 'Karla Bold';
      font-size: 50px;
      line-height: 55px;
    }
  }
  .type-p1 {
    font-family: Arial;
    font-size: 16px;
    line-height: 22px;
    html[lang^="de"] & {
      font-family: 'Karla Regular';
      font-size: 16px;
      line-height: 22px;
    }
  }
}
@media only screen and (min-width: 768px) {
  .type-h2 {
    font-family: Arial;
    font-size: 80px;
    line-height: 90px;
    html[lang^="de"] & {
      font-family: 'Karla Bold';
      font-size: 80px;
      line-height: 90px;
    }
  }
  .type-p1 {
    font-family: Arial;
    font-size: 19px;
    line-height: 26px;
    html[lang^="de"] & {
      font-family: 'Karla Regular';
      font-size: 19px;
      line-height: 26px;
    }
  }
}

(Die Schriftgröße und Zeilenhöhe werden für die Überschriftenklasse (.type-h2) und den Absatz (.type-p1) je nach Haltepunkt und Gebietsschema neu definiert.)

Sowie Stile direkt für das Banner:

/*
banner.scss
*/
@import 'path/to/typography.scss';
.banner {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background: url('path/to/banner-image.png') no-repeat center bottom;
  background-size: cover;
  &__content {
    color: #fff;
    padding: 48px 0 48px 48px;
    &-title {
      @extend .type-h2;
    }
    &-description {
      @extend .type-p1;
      max-width: 80%;
      margin-top: 24px;
    }
    &-links {
      @extend .type-p1;
      display: flex;
      flex-direction: row;
      margin-top: 24px;
      li {
        margin-left: 18px;
        &:first-child {
          margin-left: 0;
        }
        a {
          color: inherit;
        }
      }
    }
  }
}

(Aus Gründen der Übersichtlichkeit werden die Bereiche, die die Einrückung anzeigen, an die visuellen Grenzen der Elemente verschoben.)

Ergebnis für das englische Gebietsschema:

Gerenderter Text ohne Typografieanpassung für das englische Gebietsschema

Ergebnis für das deutsche Gebietsschema (der Titel wurde im Vergleich zur englischen Version geändert, um den Bereich der diakritischen Zeichen zu demonstrieren) :

Gerenderter Text ohne Typografieanpassung für das deutsche Gebietsschema

Wie erwartet der tatsächliche Wert der Einrückung (24 Pixel) ) wurde ergänzt durch leere Bereiche mit Zeilenhöhe und Begrenzungsrahmen der Schrift, einen Bereich zum Zeichnen von Diakritika sowie einen Bereich mit nach unten gerichteter Schrifthöhe.

Um das gewünschte Ergebnis zu erzielen, wurden die folgenden Ansätze in Betracht gezogen:

1. Reduzieren der Zeilenhöhe des Textelements.

Nachteile:

- Nicht für mehrzeiligen Text geeignet, da dies die Überschrift beeinflusst.
- Wenn Sie auf den tatsächlichen Wert fallen, bleiben bei der Schrifthöhe leere Bereiche des Begrenzungsrahmens der Schrift - Schultern.

2. Versetzen Sie die Texthöhe auf „zusätzliche“ Höhe, indem Sie negative Einrückungswerte des Textelements selbst (oder dessen Enthalten) oder alternativ seines Pseudoelements verwenden.

  .selector {
    margin-top: -6px;
  }
  .selector-2:before {
    content: '';
    display: table;
    margin-top: -6px;
  }

Nachteile:

  • Beeinflusst Stile eines Elements oder Pseudoelements, die möglicherweise bereits verwendet werden.
  • Es erfordert eine manuelle Berechnung und Angabe unterschiedlicher Werte, wenn unterschiedliche Schriftfamilien für unterschiedliche Lokalisierungen verwendet werden, was die Erstellung zusätzlicher Regeln impliziert.
  • Wenn Sie die grundlegenden typografischen Stile der Anwendung oder die Schriftarten ändern, müssen alle Werte neu berechnet werden (aufgrund der unterschiedlichen Textmetriken der neuen Schriftart).

3. Reduzieren Sie die Größe des Schriftbegrenzungsrahmens auf die Glyphen-Rendering-Grenzen, indem Sie die Schriftart selbst ändern.

Nachteile:

  • Nicht für Systemschriftarten geeignet.
  • Nicht für lizenzierte Schriftarten geeignet, da dies gegen die Nutzungsbedingungen und / oder Änderungen verstoßen kann.
  • Löst nicht das Problem der Kompensation des Bereichs diakritischer Zeichen (z. B. für Zeichen wie Й, Ё, È, Ñ, Ÿ) über dem oberen Rand des Großbuchstabens (Großbuchstaben) und dem Bereich der absteigenden Höhe (absteigende Höhe) (z. B. für Zeichen wie p) , g, j).

4. Verringern Sie den Wert der Einrückung, die verwendet wird, um den gewünschten Wert visuell anzupassen.

Nachteile:

  1. Es erfordert eine Berechnung des Werts in Abhängigkeit von den typografischen Stilen des Ziels und / oder des verwendeten benachbarten Elements, abhängig von den typografischen Stilen und Textmetriken der verwendeten Schriftart.
  2. Erfordert unterschiedliche Werte, wenn unterschiedliche Schriftfamilien für unterschiedliche Lokalisierungen verwendet werden. Dies erfordert die manuelle Erstellung zusätzlicher Regeln.
  3. Das Ändern der grundlegenden typografischen Stile der Site und / oder das Ersetzen der Schriftarten impliziert eine Nachzählung der verwendeten Werte (aufgrund der unterschiedlichen Textmetriken der neuen Schriftart).
  4. Das Vorhandensein zusätzlicher Regeln für verschiedene Lokalisierungen und / oder Medienabfragen (Medienabfragen) impliziert die manuelle Erstellung und Berechnung aller möglichen Kombinationen.

Von den aufgelisteten Methoden zur Lösung des vorgestellten Problems ist Punkt 4 die zuverlässigste und genaueste, aber gleichzeitig zeitaufwändigste.

Für Anwendungen, die verschiedene Haltepunkte und mehrere Lokalisierungen unterstützen, bedeutet dies, dass die auf die verwendeten Deklarationen angewendeten Werte genau berechnet werden müssen Erstellen Sie zusätzliche Regeln, die Medienabfragen, Lokalisierungsselektoren sowie Textmetriken der verwendeten Schriftarten berücksichtigen. Zweifel, um es milde auszudrücken, sind zweifelhaft. Darüber hinaus erhöht die Zeit, die für die Beschreibung der genauen Stile und deren anschließende Überprüfung aufgewendet wird, die Entwicklungszeit, wodurch sowohl Entwicklern als auch Testern Routinearbeiten hinzugefügt werden.

Um den Prozess der Neuberechnung von Einrückungen zwischen Textelementen basierend auf typografischen Regeln und Textmetriken für verwendete Schriftarten sowie die automatisierte Unterstützung aller abhängigen Kombinationen in typografischen Stilen zu automatisieren, wurde das Postcss-Plugin postcss-text-indentation-adjust erstellt

PostCSS Plugin Postcss-Text-Einrückung-Anpassung


postcss-text-indentation-adjust - postcss-Plugin, mit dem Sie die in Stilen verwendeten Einrückungswerte unter Berücksichtigung typografischer Stile sowie der Textmetriken der verwendeten Schriftarten anpassen können.

Der Arbeitsalgorithmus:

1. Extrahieren von Textmetriken, die im Schriftprojekt verwendet werden.
2. Extrahieren von Daten aus verwendeten typografischen Stilen.
3. Initialisierung des Plugins und dessen Einbeziehung in den Assemblierungsprozess.
4. Beschreibung der Anpassung des Werts der Deklaration unter Verwendung einer speziellen Syntax mit typografischen Selektoren.
5. Zusammenstellen des Projekts und Erhalten des Ergebnisses von Anpassungen mit allen möglichen Kombinationen externer Regeln für typografische Stile (Medienabfragen, übergeordnete Selektoren und deren Kombinationen).

Vorteile:

  1. Der ursprüngliche Einrückungswert wird verwendet (z. B. aus einem Entwurfslayout oder einem typografischen Stilleitfaden), mit dem Sie diese Werte zentral in Variablen speichern und bei Änderung der Entwurfsanforderungen die Anfangswerte einfach ändern können.
  2. Der Einrückungswert wird so angepasst, dass leere Bereiche mit Zeilenhöhe, Schriftbegrenzungsrahmen, diakritischem Zeichenbereich und absteigender Schrifthöhe mithilfe typografischer Stilwerte für Textelemente, von denen Sie den Abstand verringern müssen, subtrahiert werden.
  3. Wenn es in typografischen Stilen mehrere Regeln gibt, die von Medienabfragen (Medienabfrage) oder bestimmten übergeordneten Selektoren abhängen (z. B. HTML [lang ^ = "de"], .parent-classname), werden die erforderlichen zusätzlichen Regeln automatisch für die Zieldeklaration erstellt. deren Wert angepasst werden muss, unter Berücksichtigung von Medienabfragen und / oder übergeordneten Selektoren sowie der Berechnung der Endwerte der Deklaration unter Berücksichtigung der verwendeten Zeilenhöhen und Textmetriken der verbundenen Schriftarten.

Ein Beispiel für die Regeln, die auf den typografischen Stil des Headers mit der Klasse .type-h2 angewendet werden und die Neudefinition der Schriftfamilie sowie deren Größe und Zeilenhöhe für eine bestimmte Bildschirmbreite und ein bestimmtes deutsches Gebietsschema beschreiben:

.type-h2 {
  font-family: Arial;
  font-size: 35px;
  line-height: 40px;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 2px;
  html[lang^="de"] & {
    font-family: 'Karla Bold';
    font-size: 38px;
    line-height: 46px;
  }
}
@media only screen and (min-width: 768px) {
.type-h2 {
  font-family: Arial;
  font-size: 80px;
  line-height: 90px;
  html[lang^="de"] & {
    font-family: 'Karla Bold';
    font-size: 86px;
    line-height: 94px;
  }
}

4. Bei Verwendung des CSS-Präprozessors (z. B. sass, scss, less) wird die Verschachtelung der verarbeiteten Regeln sowie die Verwendung von Variablen unterstützt.

Die Genauigkeit der Plug-In-Korrekturen hängt von den Textmetriken der Schriftarten ab, die zum Zeitpunkt der Initialisierung als Argument übergeben wurden. Bevor wir also das Plug-In für die Anpassung von Post-CSS-Texteinrückungen in unser Beispiel integrieren, werden wir prüfen, wie Textmetriken extrahiert werden können.

Abrufen von Textmetriken


Beschrieben weitere Verfahren in einem separaten Paket entwickelt , Textmetrik Extrahieren font-Metriken und ermöglichen Textmetrik aus einem lokal gespeicherten, System zu empfangen oder entfernt angeordnet Schriftarten durch die Verwendung von CSS Font Laden API , indem Sie den Text auf der Leinwand in Chrome - Browser zeichnen , wenn die Fahne «experimentalCanvasFeatures: true» Anschließend werden die Werte in einer Datei gespeichert.

Um Textmetriken zu extrahieren, verwenden wir die Canvas-Kontextmethode MeasureText . Nach Angaben der Dokumentation Textmetrics nur Wert Textmetrics - Objekt , wenn im Browser Rendering - die Breite des gerenderten Textes ( Breite ).

Um unser Problem zu lösen, sind detailliertere Parameter erforderlich, z. B. fontBoundingBoxAscent (Abstand von der Grundlinie zum oberen Rand des Schriftbegrenzungsrahmens), fontBoundingBoxDescent (Abstand zwischen der Grundlinie und dem unteren Rand des Schriftbegrenzungsrahmens) sowie alphabetische Grundlinie (der Abstand zwischen der zum Zeichnen ausgewählten Basislinie)und die alphabetische Basislinie) und die hängende Basislinie (der Abstand zwischen der für das Rendern ausgewählten Basislinie und dem oberen Rand des Glyphen-Renderings ohne Berücksichtigung des Bereichs der diakritischen Zeichen), die nur in Chrom verfügbar sind, wenn das Flag ExperimentalCanvasFeatures: true aktiviert ist.

Die Summe der Werte für fontBoundingBoxAscent und fontBoundingBoxDescent gibt die tatsächliche Höhe des Zeichenbereichs des Schriftbegrenzungsrahmens an, und die Differenz zwischen den Werten für die hängende Basislinie und die alphabetische Basislinie ergibt die tatsächliche Kappenhöhe ohne diakritische Zeichen, Schultern und absteigende Höhen.

Da die Werte in CSS-Pixeln dargestellt werden und relativ zum zum Rendern des Texts verwendeten Schriftgrößenwert berechnet werden, können Sie das Verhältnis der Differenz zwischen der Höhe des Schriftbegrenzungsrahmens und der Höhe des Großbuchstabens zur Höhe des Großbuchstabens verwenden. Auf diese Weise können Sie die relative Höhe ausgeschlossener Bereiche für die in unseren Stilen verwendete Zielschriftgröße berechnen.

Aber das Wichtigste zuerst.

Starten von Chrome mit dem ExperimentalCanvasFeatures-Flag


Wir benötigen eine HTML-Seite mit einer darauf erstellten Zeichenfläche, die für unser Skript verfügbar ist.
Verwenden Sie die Nightmare- Bibliothek, um die Zeichenfläche in einem Browser mit aktiviertem ExperimentalCanvasFeatures-Flag zu bearbeiten :

import Nightmare from 'nightmare';
import fse from 'fs-extra';
const browser = Nightmare({
  show: false,
  webPreferences: {
    experimentalCanvasFeatures: true
  }
});
const pageUrl = 'your/path/to/canvas/page';
// параметры шрифтов, относительно которых нужно снять текстовые метрики
const fontsData = {
    fonts: [{
    fontFamily: 'Arial'
  }, {
    fontFamily: 'Karla Regular',
    src: '//fonts.gstatic.com/s/karla/v6/S1bXQ0LrY7AzefpgNae9sYDGDUGfDkXyfkzVDelzfFk.woff2'
  }, {
    fontFamily: 'Karla Bold',
    src: '//fonts.gstatic.com/s/karla/v6/r3NqIkFHFaF3esZDc3WT5BkAz4rYn47Zy2rvigWQf6w.woff2'
  }],
  fontSize: 24
};
browser.gotTo(pageUrl)
  .evaluate(data => {
    // Так как часть шрифтов может быть расположена удаленно и потребовать время на загрузку - используем Promise
    return new window.Promise((rootResolve, rootReject) => {
      const {fonts, fontSize} = data;
      // При наличии не системных, а подключаемых извне или локально шрифтов, добавим их в очередь на загрузку, обернув в Promise
      const fontsToLoad = fonts.reduce((result, fontData) => {
        const {src, fontFamily} = fontData;
        // При остутствии параметра src будем считать, что используется системный шрифт
        if (typeof src === 'string') {
          return result;
        }
        const promise = new window.Promise((resolve, reject) => {
            // Для подключения нового шрифта воспользуемся конструктором FontFace
            const fontFace = new window.FontFace(fontFamily, `url(${encodeURI(src)})`);
            // и добавим новый font face, когда шрифт будет загружен
            fontFace.load().then(function () {
              document.fonts.add(fontFace);
              resolve();
            }).catch(function (err) {
              reject(err);
            });
          });
          return promise;
      }, []);
      const fontsMetrics = {};
      // Как только все шрифты загружены - последовательно отрисуем их на холсте и извлечем текстовые метрики
      window.Promise.all(fontsToLoad).then(() => {
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        // В качестве базовой линии используем алфавитную базовую линию
        ctx.textBaseline = 'alphabetical';
        fonts.forEach(fontData => {
          // Применим шрифт к холсту и извлечем текстовые метрики
          ctx.font = `${fontSize}px ${fontData.fontFamily}`;
          const metrics = ctx.measureText('Example');
          fontsMetrics[fontData.fontFamily] = metrics;
        });
      });
      rootResolve(fontsMetrics);
    });
  }, fontsData)
  .end()
  .then(result => {
    // Сохраним текстовые метрики в файл для последующего использования
    const content = JSON.stringify(result, null, 4);
    fse.outputFile('desired/path/to/metrics.json', content, function (err) {
      if (err) {
        console.error(err);
      }
    });
  });

Als Ergebnis erhalten wir die Textmetriken der erforderlichen Schriftarten:

{
  "Arial": {
    "actualBoundingBoxAscent": 0,
    "actualBoundingBoxDescent": 24,
    "actualBoundingBoxLeft": 0,
    "actualBoundingBoxRight": 93,
    "alphabeticBaseline": 0,
    "emHeightAscent": 0,
    "emHeightDescent": 0,
    "fontBoundingBoxAscent": 22,
    "fontBoundingBoxDescent": 5,
    "hangingBaseline": 17.600000381469727,
    "ideographicBaseline": -5,
    "width": 93.375
  },
  "Karla Bold": {
    "actualBoundingBoxAscent": 0,
    "actualBoundingBoxDescent": 24,
    "actualBoundingBoxLeft": 0,
    "actualBoundingBoxRight": 85,
    "alphabeticBaseline": 0,
    "emHeightAscent": 0,
    "emHeightDescent": 0,
    "fontBoundingBoxAscent": 22,
    "fontBoundingBoxDescent": 6,
    "hangingBaseline": 17.600000381469727,
    "ideographicBaseline": -6,
    "width": 85.30078125
  },
  "Karla Regular": {
    "actualBoundingBoxAscent": 0,
    "actualBoundingBoxDescent": 24,
    "actualBoundingBoxLeft": 0,
    "actualBoundingBoxRight": 85,
    "alphabeticBaseline": 0,
    "emHeightAscent": 0,
    "emHeightDescent": 0,
    "fontBoundingBoxAscent": 22,
    "fontBoundingBoxDescent": 6,
    "hangingBaseline": 17.600000381469727,
    "ideographicBaseline": -6,
    "width": 85.30078125
  }
}

In diesem Beispiel sind Textmetriken nur für die Arial-, Karla Bold- und Karla Regular-Schriftarten erforderlich. In der Praxis kann es sich jedoch um jede verfügbare Systemschriftart, benutzerdefinierte Schriftart oder über CDN in der Menge handeln, die zur Unterstützung aller Lokalisierungen Ihres Projekts erforderlich ist.

Der Vorgang zum Abrufen von Textmetriken ist in der Regel ein einmaliger Vorgang und sollte nur neu gestartet werden, wenn sich die im Projekt verwendeten Schriftarten ändern. In den meisten Fällen reicht es aus, Werte einmal zu generieren, in einer Datei zu speichern und während der Montage zu verwenden.

Mit dem Font-Metrics-Paket wird das Generieren von Textmetriken erheblich vereinfacht:

import fontMetrics from 'font-metrics';
const fontParser = fontMetrics({
  fonts: [{
    fontFamily: 'Arial'
  }, {
    fontFamily: 'Karla Regular',
    src: '//fonts.gstatic.com/s/karla/v6/S1bXQ0LrY7AzefpgNae9sYDGDUGfDkXyfkzVDelzfFk.woff2'
  }, {
    fontFamily: 'Karla Bold',
    src: '//fonts.gstatic.com/s/karla/v6/r3NqIkFHFaF3esZDc3WT5BkAz4rYn47Zy2rvigWQf6w.woff2'
  }],
  output: './font-metrics',
  filename: 'font-metrics.json'
});
fontParser.parse();

Ergebnis:

{
  "metrics": {
    "Arial": {
      "_fontSize": 24,
      "_textBaseline": "alphabetic",
      "actualBoundingBoxAscent": 0,
      "actualBoundingBoxDescent": 24,
      "actualBoundingBoxLeft": 0,
      "actualBoundingBoxRight": 93,
      "alphabeticBaseline": 0,
      "emHeightAscent": 0,
      "emHeightDescent": 0,
      "fontBoundingBoxAscent": 22,
      "fontBoundingBoxDescent": 5,
      "hangingBaseline": 17.600000381469727,
      "ideographicBaseline": -5,
      "width": 93.375
    },
    "Karla Bold": {
      "_fontSize": 24,
      "_textBaseline": "alphabetic",
      "actualBoundingBoxAscent": 0,
      "actualBoundingBoxDescent": 24,
      "actualBoundingBoxLeft": 0,
      "actualBoundingBoxRight": 85,
      "alphabeticBaseline": 0,
      "emHeightAscent": 0,
      "emHeightDescent": 0,
      "fontBoundingBoxAscent": 22,
      "fontBoundingBoxDescent": 6,
      "hangingBaseline": 17.600000381469727,
      "ideographicBaseline": -6,
      "width": 85.30078125
    },
    "Karla Regular": {
      "_fontSize": 24,
      "_textBaseline": "alphabetic",
      "actualBoundingBoxAscent": 0,
      "actualBoundingBoxDescent": 24,
      "actualBoundingBoxLeft": 0,
      "actualBoundingBoxRight": 85,
      "alphabeticBaseline": 0,
      "emHeightAscent": 0,
      "emHeightDescent": 0,
      "fontBoundingBoxAscent": 22,
      "fontBoundingBoxDescent": 6,
      "hangingBaseline": 17.600000381469727,
      "ideographicBaseline": -6,
      "width": 85.30078125
    }
  },
  "src": [
    {
      "fontFamily": "Arial"
    },
    {
      "fontFamily": "Karla Regular",
      "src": "//fonts.gstatic.com/s/karla/v6/S1bXQ0LrY7AzefpgNae9sYDGDUGfDkXyfkzVDelzfFk.woff2"
    },
    {
      "fontFamily": "Karla Bold",
      "src": "//fonts.gstatic.com/s/karla/v6/r3NqIkFHFaF3esZDc3WT5BkAz4rYn47Zy2rvigWQf6w.woff2"
    }
  ]
}

Integration des Plugins zur Anpassung von Postcss-Text-Einrückungen


Das Funktionsprinzip des Postcss-Text-Indentation-Adjustment-Plugins basiert auf der Beschreibung der Anpassungen des auf die Deklaration angewendeten Anfangswertes (in diesem Beispiel 24px) mit den typografischen Klassen, für die dieser Wert angepasst werden muss. Die Beschreibung der Anpassung erfolgt in Form eines Kommentars innerhalb des Werts der Deklaration und ermöglicht Ihnen die sichere Implementierung des Plug-Ins in der Projektassembly.

Überlegen Sie, wie Anpassungen für unser Beispiel beschrieben werden können:

/*
banner.scss
*/
@import 'path/to/typography.scss';
.banner {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background: url('path/to/banner-image.png') no-repeat center bottom;
  background-size: cover;
  &__content {
    color: #fff;
    padding: 48px 0 48px 48px /* {48px, .type-h2} 0 {48px, .type-p1} 48px */;
    &-title {
      @extend .type-h2;
    }
    &-description {
      @extend .type-p1;
      max-width: 80%;
      margin-top: 24px /* {24px, .type-h2, .type-p1} */;
    }
    &-links {
      @extend .type-p1;
      display: flex;
      flex-direction: row;
      margin-top: 24px /* {24px, .type-p1, .type-p1} */;
      li {
        margin-left: 18px;
        &:first-child {
          margin-left: 0;
        }
        a {
          color: inherit;
        }
      }
    }
  }
}

Anpassungsverarbeitung


Wir importieren die notwendigen Bibliotheken.

// node-sass для компиляции исходного файла типографических стилей
import nodeSass from 'node-sass';
// postcss для манипуляции со стилями
import postcss from 'postcss';
// fse или fs для чтения исходного файла типографических стилей и сохранения результата
import fse from 'fs-extra';
// path для нормализации пути к файлу
import path from 'path';
// postcss-scss для использования postcss до компиляции scss файлов в css
import postcssSCSS from 'postcss-scss';
// postcss-text-indentation-adjustment для парсинга типографических стилей, создания корректировок и комбинаций зависимых правил
import textIndentationAdjustment, {parser} from 'postcss-text-indentation-adjustment';
// postcss-partial-import для инлайн ипорта scss файлов, использованных в основных стилях проекта
import postcssPartialImport from 'postcss-partial-import';
// css-mqpacker для группировки медиа-запросов (или любой другой инструмент)
import cssMqPacker from 'css-mqpacker';
// postcss-merge-rules для объединения css селекторов на основании идентичных деклараций (или любой другой инструмент)
import mergeRules from 'postcss-merge-rules';
// Текстовые метрики, извлеченные на одном из предыдущих шагов
import {metrics} from 'path/to/metrics.json';
// Скомпилируем типографические стили из scss в css для их последующего парсинга
const typography = nodeSass.renderSync({
  file: 'path/to/typography.scss'
}).css.toString();
// Инициализируем парсер, передав текстовые метрики, полученные на одном из предыдущих шагов
const typographyParser = parser({
  metrics: metrics
});
// Распарсим типографические стили для их последующего использования
const parsedTypography = typographyParser.parse(typography);
// Инициализируем postcss плагин, передав подоготовленные парсером данные типографических стилей
const typographyAdjustmentPlugin = textIndentationAdjustment({
  corrections: parsedTypography,
  plainCSS: false // при использовании плагина для корректировки значений на этапе препроцессинга стилей (например, при использовании scss)
});
// Используем postcss с синтаксисом scss
fse.readFile('path/to/banner.scss', (err, scss) => {
  postcss([postcssPartialImport(), postcssTypographyAdjustmentPlugin])
    .process(scss, {
      syntax: postcssSCSS,
      from: 'path/to/banner.scss',
      to: `path/to/banner.css`
    })
    .then(postcssResult => {
      return new Promise((resolve, reject) => {
        nodeSass.render({
          data: postcssResult.css,
          outputStyle: 'expanded'
        }, (err, result) => {
          resolve(result);
        });
      });
    })
    .then(result => {
      // Объединим медиа-запросы и правила с одинаковыми декларациями
      return postcss([mergeRules(), cssMqPacker()]).process(result.css);
    })
    .then(result => {
      fse.outputFile('path/to/banner.css', result.css);
    })
    .catch(e => {
      console.log(e);
    });
});

Infolgedessen wird eine Datei mit den folgenden Regeln kompiliert (typografische Stile und die Ergebnisse von @extend werden ausgeschlossen, um die generierten Korrekturen hervorzuheben) :

.banner {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background: url("path/to/banner-image.png") no-repeat center bottom;
  background-size: cover;
}
.banner__content {
  color: #fff;
  padding: 39.5px 0 43px 48px;
}
.banner__content-description {
  max-width: 80%;
  margin-top: 10.5px;
}
html[lang^="de"] .banner__content-description {
  margin-top: 10.5px;
}
.banner__content-links {
  display: flex;
  flex-direction: row;
  margin-top: 14px;
}
.banner__content-links li {
  margin-left: 18px;
}
.banner__content-links li:first-child {
  margin-left: 0;
}
.banner__content-links li a {
  color: inherit;
}
html[lang^="de"] .banner__content-links {
  margin-top: 14px;
}
html[lang^="de"] .banner__content {
  padding: 39.5px 0 43px 48px;
}
@media only screen and (min-width: 480px) and (max-width: 767px) {
  .banner__content-description {
    margin-top: 8.5px;
  }
  html[lang^="de"] .banner__content-description {
    margin-top: 7.5px;
  }
  .banner__content-links {
    margin-top: 14px;
  }
  html[lang^="de"] .banner__content-links {
    margin-top: 14px;
  }
  .banner__content {
    padding: 37.5px 0 43px 48px;
  }
  html[lang^="de"] .banner__content {
    padding: 36.5px 0 43px 48px;
  }
}
@media only screen and (min-width: 768px) {
  .banner__content-description {
    margin-top: -0.5px;
  }
  html[lang^="de"] .banner__content-description {
    margin-top: -1.5px;
  }
  .banner__content-links {
    margin-top: 11px;
  }
  html[lang^="de"] .banner__content-links {
    margin-top: 11px;
  }
  .banner__content {
    padding: 30px 0 41.5px 48px;
  }
  html[lang^="de"] .banner__content {
    padding: 29px 0 41.5px 48px;
  }
}

Ergebnis für das englische Gebietsschema:







Ergebnis für das deutsche Gebietsschema:







Wie Sie sehen, wurde das Ergebnis des Renderns der Einrückung erheblich angepasst.

Anpassungssyntax


(Kompilierte Werte werden zusätzlich über die Plugins zum Kombinieren von Selektoren und Medienabfragen übergeben - css-mqpacker, postcss-merge-rules)

1. Anpassungen werden in Form eines Kommentars vorgenommen und befinden sich innerhalb des Deklarationswerts .

.rule-selector {
  padding-top: 24px /*  */;
}

2. Jeder Wert, der angepasst werden muss, wird in geschweifte Klammern gesetzt (Korrekturgruppe).

.rule-selector {
  padding-top: 24px /* {24px} */;
}

3. Typografische Klassen oder Tags, für die Korrekturen vorgenommen werden sollen, werden nach dem Basiswert mit einem Komma gekennzeichnet.

.rule-selector {
  padding-top: 24px /* {24px, h3, .type-h2} */;
}

4. Wenn Sie mehrere Werte angeben müssen, wird jeder von ihnen in eine eigene Korrekturgruppe eingefügt, die durch den berechneten Wert ersetzt wird.

.rule-selector {
  padding-top: 24px 0 24px /* {24px, h3, .type-h2} 0 {24px, .type-h2, .copy-p1} */;
}

5. Der Inhalt des Kommentars mit dem Ergebnis der Berechnung aller Korrekturgruppen wird vom Plugin im Endwert der Deklaration festgelegt.

.rule-selector {
  padding-top: 17px 0 19px;
}

6. Wenn die Quelldatei typografischer Klassen übergeordnete Selektoren enthält, wird eine zusätzliche Regel erstellt, die eine Kombination aus übergeordnetem und Zielselektor sowie Deklarationen mit berechneten Werten für alle Kombinationen typografischer Selektoren enthält.

/* typography */
.p1 {
  font-size: 16px;
  line-height: 24px;
  font-family: Arial;
  .parent-selector-1 & {
    font-size: 18px;
    line-height: 26px;
    font-family: Arial;
  }
}
.p2 {
  font-size: 18px;
  line-height: 22px;
  font-family: Arial;
  .parent-selector-2 & {
    font-size: 14px;
    line-height: 20px;
    font-family: Arial;
  }
}

/* input */
.rule-selector {
  padding-top: 24px /* {24px, .p1, .p2} */;
}

/* output */
.rule-selector {
  padding-top: 13px;
}
.parent-selector-1 .rule-selector {
  padding-top: 12px;
}
.parent-selector-2 .rule-selector {
  padding-top: 13px;
}

7. Wenn Medienabfragen oder Medienabfragen in Kombination mit übergeordneten Selektoren vorhanden sind, werden alle möglichen Kombinationen für typografische Selektoren erstellt, die an der Anpassung beteiligt sind.

/* typography */
.p1 {
  font-size: 16px;
  line-height: 24px;
  font-family: Arial;
  .parent-selector-1 & {
    font-size: 18px;
    line-height: 26px;
    font-family: Arial;
  }
  @media (min-width: 768px) {
    font-size: 22px;
    line-height: 28px;
    font-family: Arial;
    html[lang^="de"] .parent-selector-3 & {
      font-size: 28px;
      line-height: 40px;
      font-family: Arial;
    }
  }
}
.p2 {
  font-size: 18px;
  line-height: 22px;
  font-family: Arial;
  .parent-selector-2 & {
    font-size: 14px;
    line-height: 20px;
    font-family: Arial;
  }
  @media (min-width: 321px) {
    font-size: 22px;
    line-height: 28px;
    font-family: Arial;
    html[lang^="de"] .parent-selector-4 & {
      font-size: 28px;
      line-height: 40px;
      font-family: Arial;
    }
  }
}

/* input */
.rule-selector {
  padding-top: 24px /* {24px, .p1, .p2} */;
}

/* output */
.rule-selector {
  padding-top: 13px;
}
.parent-selector-1 .rule-selector {
  padding-top: 12px;
}
.parent-selector-2 .rule-selector {
  padding-top: 13px;
}
@media (min-width: 768px) {
  .rule-selector {
    padding-top: 13px;
  }
  html[lang^="de"] .parent-selector-3 .rule-selector {
    padding-top: 14px;
  }
}
@media (min-width: 321px) {
  .rule-selector {
    padding-top: 12px;
  }
  html[lang^="de"] .parent-selector-4 .rule-selector {
    padding-top: 14px;
  }
}

8. Sie können die Parameter zur Berechnung der Endwerte mit dem Flag --debug überprüfen

/* input */
.rule-selector {
  padding-top: 24px /* {24px, .p1, .p2} --debug */;
}

Infolgedessen wird ein Teil der Daten, die zum Erstellen der Anpassung verwendet wurden, in der Konsole angezeigt.

Zum Zeitpunkt des Schreibens der Artikelversion (1.0.9) relevante Nutzungsmerkmale


  • Alle in der Berechnung verwendeten Werte müssen in Pixel angegeben werden.
  • Jede Regel in typografischen Stilen muss Schriftparameter wie Schriftfamilie, Schriftgröße und Zeilenhöhe enthalten, die separat angegeben oder zu einer einzigen Schriftdeklaration kombiniert werden.
  • Bei Verwendung mit Präprozessoren in der Phase der Vorkompilierung von Stilen muss die Option plainCSS auf false gesetzt werden.

const typographyAdjustmentPlugin = textIndentationAdjustment({
  corrections: parsedTypography,
  plainCSS: false
});

Abschließend


  • Es verkürzt die Zeit für die Entwicklung sich ständig weiterentwickelnder Anwendungen, die verschiedene Haltepunkte und verschiedene Lokalisierungen unterstützen, wobei der Genauigkeit von Layout und Design große Bedeutung beigemessen wird.
  • Es ist für jede Schriftart leicht anpassbar. Es reicht aus, Textmetriken nur einmal zu extrahieren und sie beim Kompilieren von Stilen zu verwenden.
  • Integriert sich in jede Art von Assembly, die von postcss unterstützt wird.
  • Ständig weiterentwickelt, um die Qualität der Korrekturen zu verbessern

Vielen Dank für Ihre Aufmerksamkeit. Ich freue mich über vernünftige Kritik sowie Verbesserungs- und Optimierungsvorschläge.

Jetzt auch beliebt: