<div class="banner"> <div class="banner__media"> <div class="banner__content"> <h2 class="banner__content-title">Men</h2> <p class="banner__content-description">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text.</p> <ul class="banner__content-links"> <li> <a href="#">Women</a> </li> <li> <a href="#">Men</a> </li> <li> <a href="#">Boys</a> </li> <li> <a href="#">Girls</a> </li> </ul> </div> </div> </div>
/* 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; } } }
/* 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; } } } } }
.selector { margin-top: -6px; } .selector-2:before { content: ''; display: table; margin-top: -6px; }
To automate the process of recalculating spacing between text elements based on typographical rules and text metrics of the fonts used, as well as automated support for all dependent combinations used in typographic styles, a postcss postcss-text-indentation-adjustment plugin was created
.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; } }
The following method for extracting text metrics is arranged in a separate font-metrics package and allows you to get text metrics from locally saved, system or remotely located fonts, using the CSS Font Loading API , drawing text on canvas in Chrome with the “experimentalCanvasFeatures: true” flag enabled followed by saving the values to a file.
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); } }); });
{ "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 } }
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();
{ "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" } ] }
/* 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; } } } } }
// 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); }); });
.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; } }
.rule-selector { padding-top: 24px /* */; }
.rule-selector { padding-top: 24px /* {24px} */; }
.rule-selector { padding-top: 24px /* {24px, h3, .type-h2} */; }
.rule-selector { padding-top: 24px 0 24px /* {24px, h3, .type-h2} 0 {24px, .type-h2, .copy-p1} */; }
.rule-selector { padding-top: 17px 0 19px; }
/* 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; }
/* 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; } }
/* input */ .rule-selector { padding-top: 24px /* {24px, .p1, .p2} --debug */; }
const typographyAdjustmentPlugin = textIndentationAdjustment({ corrections: parsedTypography, plainCSS: false });
Source: https://habr.com/ru/post/344984/
All Articles