Tipografi Responsif Cairan Dengan Ukuran Cairan Poli CSS
Diterbitkan: 2022-03-10Pada artikel ini, kita akan membawanya ke level lain. Kami akan memeriksa cara membuat tipografi yang dapat diskalakan dan lancar di beberapa titik henti sementara dan ukuran font yang telah ditentukan sebelumnya menggunakan fitur browser yang didukung dengan baik dan beberapa aljabar dasar. Bagian terbaiknya adalah Anda dapat mengotomatiskan semuanya dengan menggunakan Sass.
Bacaan Lebih Lanjut tentang SmashingMag:
- Tipografi yang Benar-Benar Cair Dengan Unit vh Dan vw
- Pola Tipografi Dalam Desain Buletin Email HTML
- Contoh Tipografi Web Yang Baik, Buruk, dan Hebat
- Alat Dan Sumber Daya Untuk Tipografi Web yang Lebih Berarti
Saat bekerja dengan desainer kreatif pada desain halaman web, cukup umum untuk menerima beberapa artboard/tata letak Sketch atau Photoshop, satu untuk setiap breakpoint. Dalam desain itu, elemen (seperti heading h1
) biasanya akan memiliki ukuran yang berbeda di setiap breakpoint. Sebagai contoh:
-
h1
pada tata letak kecil bisa menjadi22px
-
h1
pada tata letak sedang bisa menjadi24px
-
h1
pada tata letak besar bisa menjadi34px
CSS minimum untuk ini menggunakan kueri media:
h1 { font-size: 22px; } @media (min-width:576px) { h1 { font-size: 22px; } } @media (min-width:768px) { h1 { font-size: 24px; } } @media (min-width:992px) { h1 { font-size: 34px; } }
Ini adalah langkah pertama yang baik, tetapi Anda membatasi font-size
hanya pada apa yang ditentukan oleh desainer pada titik henti sementara yang disediakan. Apa yang akan dikatakan desainer jika Anda bertanya, “Berapa font-size
pada viewport lebar 850px?” Jawabannya dalam banyak kasus adalah bahwa itu akan berada di antara 24px dan 34px. Namun saat ini, ukurannya hanya 24px menurut CSS Anda, yang mungkin tidak seperti yang dibayangkan oleh perancang.
Pilihan Anda saat ini adalah menghitung ukuran yang seharusnya dan menambahkan breakpoint lain. Itu cukup mudah. Tapi bagaimana dengan semua resolusi lainnya? Berapa font-size
pada lebar 800px? Bagaimana dengan 900px? Bagaimana dengan 935px? Jelas perancang tidak akan memberi Anda tata letak penuh untuk setiap kemungkinan resolusi. Bahkan jika ya, haruskah Anda menambahkan lusinan (atau ratusan) titik henti sementara untuk semua font-sizes
berbeda yang diinginkan oleh perancang? Tentu saja tidak.
Tata letak Anda sudah diskalakan dengan lancar dengan lebar viewport Anda. Bukankah lebih baik jika tipografi Anda dapat diprediksi diskalakan dengan tata letak cairan Anda? Apa lagi yang bisa kita lakukan untuk memperbaiki ini?
Unit Viewport Untuk Menyelamatkan?
Unit viewport adalah langkah lain ke arah yang benar. Mereka memungkinkan teks Anda untuk mengubah ukuran dengan lancar dengan tata letak Anda. Dan dukungan browser sangat bagus akhir-akhir ini.
Tetapi kelangsungan hidup unit Viewport sangat bergantung pada desain kreatif asli untuk halaman web. Akan sangat bagus untuk mengatur font-size
Anda menggunakan vw
dan selesai:
h1 { font-size: 2vw; }
Tetapi ini hanya berfungsi jika papan seni kreatif Anda memperhitungkannya. Apakah perancang memilih ukuran teks yang tepat 2% dari lebar masing-masing papan seninya? Tentu saja tidak. Mari kita hitung berapa nilai vw
yang dibutuhkan untuk setiap breakpoint kita:
Ukuran 22px
@ lebar 576px
= 22 576 *100 = 3.82vw Ukuran 24px
@ lebar 768px
= 24 768 *100 = 3.13vw Ukuran 34px
@ lebar 992px
= 34 992 *100 = 3.43vw
Mereka dekat tapi tidak semuanya sama. Jadi, Anda masih perlu menggunakan kueri media untuk transisi antara ukuran teks dan masih akan ada lompatan. Dan pertimbangkan efek samping yang aneh ini:
@ 767px, 3,82% dari lebar viewport adalah 29px. Jika area pandang lebih lebar 1 piksel, font-size
tiba turun kembali ke 24 piksel . Animasi area pandang yang diubah ukurannya ini menunjukkan efek samping yang tidak diinginkan ini:
Perubahan dramatis dalam ukuran font ini hampir pasti tidak seperti yang dibayangkan oleh sang desainer. Jadi bagaimana kita memecahkan masalah ini?
Regresi Linier Statistik?
Tunggu. Apa? Ya, ini adalah artikel tentang CSS, tetapi beberapa matematika dasar dapat memberikan solusi yang elegan untuk masalah kita.
Pertama, mari kita plot resolusi kita dan ukuran teks yang sesuai pada grafik:
Di sini Anda dapat melihat sebar plot ukuran teks yang ditentukan desainer pada lebar viewport yang ditentukan. Sumbu x adalah lebar viewport dan sumbu y adalah font-size
. Lihat garis itu? Itu disebut garis tren . Ini adalah cara untuk menemukan nilai font-size
yang diinterpolasi untuk lebar area pandang apa pun, berdasarkan data yang diberikan.
Garis Tren Adalah Kunci Dari Semua Ini
Jika Anda dapat mengatur font-size
Anda sesuai dengan garis tren ini, Anda akan memiliki h1 yang dengan mulus menskalakan semua resolusi yang akan mendekati pencocokan apa yang dimaksudkan oleh perancang. Pertama, mari kita lihat matematikanya. Garis lurus didefinisikan oleh persamaan ini:
- m = kemiringan
- b = perpotongan y
- x = lebar viewport saat ini
- y =
font-size
yang dihasilkan
Ada beberapa metode untuk menentukan kemiringan dan perpotongan y. Ketika beberapa nilai terlibat, metode yang umum adalah kecocokan Kuadrat Terkecil:
Setelah Anda menjalankan perhitungan tersebut, Anda memiliki persamaan garis tren.
Bagaimana Saya Menggunakan Ini Di CSS?
Oke, ini menjadi cukup berat pada matematika. Bagaimana kita benar-benar menggunakan hal ini dalam pengembangan web front-end? Jawabannya adalah CSS calc()
! Sekali lagi, teknologi CSS yang cukup baru didukung dengan sangat baik.
Anda dapat menggunakan persamaan garis tren seperti ini:
h1 { font-size: calc({slope}*100vw + {y-intercept}px); }
Setelah Anda menemukan kemiringan Anda dan y-intercept, Anda cukup mencolokkannya!
Catatan: Anda harus mengalikan kemiringan dengan 100
karena Anda menggunakannya sebagai unit vw
yang merupakan 1/100 lebar Viewport.
Bisakah Ini Menjadi Otomatis?
Saya mem-porting metode kuadrat terkecil ke dalam fungsi Sass yang mudah digunakan:
/// least-squares-fit /// Calculate the least square fit linear regression of provided values /// @param {map} $map - A Sass map of viewport width and size value combinations /// @return Linear equation as a calc() function /// @example /// font-size: least-squares-fit((576px: 24px, 768px: 24px, 992px: 34px)); /// @author Jake Wilson <[email protected]> @function least-squares-fit($map) { // Get the number of provided breakpoints $length: length(map-keys($map)); // Error if the number of breakpoints is < 2 @if ($length < 2) { @error "leastSquaresFit() $map must be at least 2 values" } // Calculate the Means $resTotal: 0; $valueTotal: 0; @each $res, $value in $map { $resTotal: $resTotal + $res; $valueTotal: $valueTotal + $value; } $resMean: $resTotal/$length; $valueMean: $valueTotal/$length; // Calculate some other stuff $multipliedDiff: 0; $squaredDiff: 0; @each $res, $value in $map { // Differences from means $resDiff: $res - $resMean; $valueDiff: $value - $valueMean; // Sum of multiplied differences $multipliedDiff: $multipliedDiff + ($resDiff * $valueDiff); // Sum of squared resolution differences $squaredDiff: $squaredDiff + ($resDiff * $resDiff); } // Calculate the Slope $m: $multipliedDiff / $squaredDiff; // Calculate the Y-Intercept $b: $valueMean - ($m * $resMean); // Return the CSS calc equation @return calc(#{$m*100}vw + #{$b}); }
Apakah ini benar-benar berfungsi? Buka CodePen ini dan ubah ukuran jendela browser Anda. Berhasil! Ukuran font cukup dekat dengan apa yang diminta oleh desain aslinya dan ukurannya sesuai dengan tata letak Anda.
Sekarang, harus diakui, itu tidak sempurna. Nilainya mendekati desain aslinya tetapi tidak sesuai. Ini karena garis tren linier adalah perkiraan ukuran font tertentu pada lebar area pandang tertentu. Ini adalah pewarisan dari regresi linier. Selalu ada beberapa kesalahan dalam hasil Anda. Ini adalah trade-off dari kesederhanaan vs akurasi. Juga, perlu diingat, semakin bervariasi ukuran teks Anda, semakin banyak kesalahan yang akan terjadi di garis tren Anda.
Bisakah kita melakukan lebih baik dari ini?
Kuadrat Terkecil Polinomial Sesuai
Untuk mendapatkan garis tren yang lebih akurat, Anda perlu melihat topik yang lebih maju, seperti garis tren regresi polinomial yang mungkin terlihat seperti ini:
Sekarang lebih seperti itu ! Jauh lebih akurat daripada garis lurus kita. Persamaan regresi polinomial dasar terlihat seperti ini:
Semakin akurat kurva yang Anda inginkan, semakin rumit persamaannya. Sayangnya, Anda tidak dapat melakukan ini di CSS . calc()
tidak bisa melakukan jenis matematika tingkat lanjut ini. Secara khusus, Anda tidak dapat menghitung eksponen:
font-size: calc(3vw * 3vw); /* This doesn't work in CSS */
Jadi sampai calc()
mendukung jenis matematika non-linier ini, kita terjebak dengan persamaan linier saja . Apakah ada hal lain yang bisa kita lakukan untuk memperbaiki ini?
Breakpoints Dan Beberapa Persamaan Linear
Bagaimana jika kita hanya menghitung garis lurus di antara setiap pasangan titik putus? Sesuatu seperti ini:
Jadi dalam contoh ini kita akan menghitung garis lurus antara 22px
dan 24px
dan kemudian antara 24px
dan 34px
. Sass akan terlihat seperti ini:
// SCSS h1 { @media (min-width:576px) { font-size: calc(???); } @media (min-width:768px) { font-size: calc(???); } }
Kita dapat menggunakan metode kuadrat terkecil yang sesuai untuk nilai calc()
tersebut, tetapi karena hanya berupa garis lurus antara 2 titik, perhitungannya dapat sangat disederhanakan. Ingat persamaan garis lurus?
Karena kita berbicara tentang hanya 2 titik sekarang, menemukan kemiringan (m) dan perpotongan y (b) adalah sepele:
Berikut adalah fungsi Sass untuk ini:
/// linear-interpolation /// Calculate the definition of a line between two points /// @param $map - A Sass map of viewport widths and size value pairs /// @returns A linear equation as a calc() function /// @example /// font-size: linear-interpolation((320px: 18px, 768px: 26px)); /// @author Jake Wilson <[email protected]> @function linear-interpolation($map) { $keys: map-keys($map); @if (length($keys) != 2) { @error "linear-interpolation() $map must be exactly 2 values"; } // The slope $m: (map-get($map, nth($keys, 2)) - map-get($map, nth($keys, 1)))/(nth($keys, 2) - nth($keys,1)); // The y-intercept $b: map-get($map, nth($keys, 1)) - $m * nth($keys, 1); // Determine if the sign should be positive or negative $sign: "+"; @if ($b < 0) { $sign: "-"; $b: abs($b); } @return calc(#{$m*100}vw #{$sign} #{$b}); }
Sekarang, cukup gunakan fungsi interpolasi linier pada beberapa breakpoint di Sass Anda. Juga, mari masukkan beberapa font-sizes
min dan maks :
// SCSS h1 { // Minimum font-size font-size: 22px; // Font-size between 576 - 768 @media (min-width:576px) { $map: (576px: 22px, 768px: 24px); font-size: linear-interpolation($map); } // Font-size between 768 - 992 @media (min-width:768px) { $map: (768px: 24px, 992px: 34px); font-size: linear-interpolation($map); } // Maximum font-size @media (min-width:992px) { font-size: 34px; } }
Dan itu menghasilkan CSS ini:
h1 { font-size: 22px; } @media (min-width: 576px) { h1 { font-size: calc(1.04166667vw + 16px); } } @media (min-width: 768px) { h1 { font-size: calc(4.46428571vw - 10.28571429px); } } @media (min-width: 992px) { h1 { font-size: 34px; } }
Cawan Suci Ukuran CSS?
Mari kita selesaikan ini semua dalam mixin Sass yang bagus (untuk yang malas dan efisien!). Saya menciptakan metode ini Poly Fluid Sizing :
/// poly-fluid-sizing /// Generate linear interpolated size values through multiple break points /// @param $property - A string CSS property name /// @param $map - A Sass map of viewport unit and size value pairs /// @requires function linear-interpolation /// @requires function map-sort /// @example /// @include poly-fluid-sizing('font-size', (576px: 22px, 768px: 24px, 992px: 34px)); /// @author Jake Wilson <[email protected]> @mixin poly-fluid-sizing($property, $map) { // Get the number of provided breakpoints $length: length(map-keys($map)); // Error if the number of breakpoints is < 2 @if ($length < 2) { @error "poly-fluid-sizing() $map requires at least values" } // Sort the map by viewport width (key) $map: map-sort($map); $keys: map-keys($map); // Minimum size #{$property}: map-get($map, nth($keys,1)); // Interpolated size through breakpoints @for $i from 1 through ($length - 1) { @media (min-width:nth($keys,$i)) { $value1: map-get($map, nth($keys,$i)); $value2: map-get($map, nth($keys,($i + 1))); // If values are not equal, perform linear interpolation @if ($value1 != $value2) { #{$property}: linear-interpolation((nth($keys,$i): $value1, nth($keys,($i+1)): $value2)); } @else { #{$property}: $value1; } } } // Maxmimum size @media (min-width:nth($keys,$length)) { #{$property}: map-get($map, nth($keys,$length)); } }
Mixin Sass ini memerlukan beberapa fungsi Sass dalam inti Github berikut:
- linear-interpolasi
- pengurutan peta
- pengurutan daftar
- hapus daftar
Mixin poly-fluid-sizing()
akan melakukan interpolasi linier pada setiap pasangan lebar viewport dan menetapkan ukuran minimum dan maksimum. Anda dapat mengimpor ini ke proyek Sass apa pun dan menggunakannya dengan mudah tanpa perlu mengetahui matematika apa pun di baliknya. Berikut adalah CodePen terakhir yang menggunakan metode ini.
Beberapa Catatan
- Jelas metode ini tidak hanya berlaku untuk
font-size
tetapi untuk properti unit/panjang apa pun (margin
,padding
, dll). Anda meneruskan nama properti yang diinginkan ke dalam mixin sebagai string. - Peta Sass dari pasangan nilai lebar + ukuran viewport dapat diteruskan dalam urutan apa pun ke dalam mixin
poly-fluid-sizing()
. Ini akan secara otomatis mengurutkan peta menurut lebar Viewport dari terendah ke tertinggi . Jadi Anda bisa melewati peta seperti ini dan itu akan berhasil dengan baik:
$map: (576px: 22px, 320px: 18px, 992px: 34px, 768px: 24px); @include poly-fluid-sizing('font-size', $map);
- Batasan untuk metode ini adalah Anda tidak dapat memasukkan unit campuran ke dalam mixin. Misalnya, lebar
3em
@576px
. Sass tidak akan benar-benar tahu apa yang harus dilakukan secara matematis di sana.
Kesimpulan
Apakah ini yang terbaik yang bisa kita lakukan? Apakah Ukuran Cairan Poli adalah Cawan Suci dari ukuran unit cairan dalam CSS? Mungkin. CSS saat ini mendukung animasi non-linear dan fungsi waktu transisi, jadi mungkin ada kemungkinan bahwa calc()
juga akan mendukungnya suatu hari nanti. Jika itu terjadi, regresi polinomial non-linier mungkin layak untuk dilihat lagi. Tapi mungkin tidak… Penskalaan linier mungkin lebih unggul.
Saya mulai mengeksplorasi ide ini pada awal 2017 dan akhirnya mengembangkan solusi di atas. Sejak itu, saya telah melihat beberapa pengembang datang dengan ide-ide serupa dan potongan-potongan berbeda dari teka-teki ini. Saya pikir sudah waktunya bagi saya untuk membagikan metode saya dan bagaimana saya sampai di sana. Unit area pandang. Kal(). Kelancangan. Breakpoint. Tak satu pun dari hal-hal ini baru. Semuanya adalah fitur browser yang telah ada selama bertahun-tahun (dengan berbagai tingkat dukungan). Saya hanya menggunakannya bersama dengan cara yang belum sepenuhnya dieksplorasi. Jangan pernah takut untuk melihat alat yang Anda gunakan setiap hari dan berpikir out-of-the-box tentang bagaimana Anda dapat menggunakannya dengan lebih baik dan mengembangkan keahlian Anda.