การพิมพ์ที่ตอบสนองต่อของไหลด้วย CSS Poly Fluid Sizing
เผยแพร่แล้ว: 2022-03-10ในบทความนี้เราจะพาไปสู่อีกระดับหนึ่ง เราจะตรวจสอบ วิธีสร้างแบบอักษรที่ปรับขนาดได้และลื่นไหล ในจุดสั่งหยุดหลายจุดและขนาดแบบอักษรที่กำหนดไว้ล่วงหน้าโดยใช้คุณสมบัติเบราว์เซอร์ที่ได้รับการสนับสนุนอย่างดีและพีชคณิตพื้นฐานบางส่วน ส่วนที่ดีที่สุดคือคุณสามารถทำให้ทุกอย่างเป็นอัตโนมัติได้โดยใช้ Sass
อ่านเพิ่มเติม เกี่ยวกับ SmashingMag:
- การพิมพ์แบบไหลอย่างแท้จริงด้วย vh และ vw Units
- รูปแบบการพิมพ์ในการออกแบบจดหมายข่าวอีเมล HTML
- ข้อดี ข้อเสีย และตัวอย่างที่ยอดเยี่ยมของการพิมพ์เว็บ
- เครื่องมือและทรัพยากรสำหรับการพิมพ์เว็บที่มีความหมายมากขึ้น
เมื่อทำงานกับครีเอทีฟดีไซเนอร์ในการออกแบบหน้าเว็บ เป็นเรื่องปกติที่จะได้รับอาร์ตบอร์ด/เลย์เอาต์ Sketch หรือ Photoshop หลายอัน อันละอันสำหรับแต่ละเบรกพอยต์ ในการออกแบบนั้น องค์ประกอบ (เช่น ส่วนหัว h1
) มักจะมีขนาดแตกต่างกันในแต่ละเบรกพอยต์ ตัวอย่างเช่น:
-
h1
ที่เลย์เอาต์ขนาดเล็กอาจเป็น22px
-
h1
ที่เลย์เอาต์ขนาดกลางอาจเป็น24px
-
h1
ที่เลย์เอาต์ขนาดใหญ่อาจเป็น34px
CSS ขั้นต่ำสุดสำหรับสิ่งนี้ใช้การสืบค้นสื่อ:
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; } }
นี่เป็นขั้นตอนแรกที่ดี แต่คุณกำลังจำกัด font-size
ให้เหลือเฉพาะสิ่งที่ผู้ออกแบบระบุไว้ที่จุดสั่งหยุดที่ให้ไว้เท่านั้น นักออกแบบจะพูดอะไรถ้าคุณถามว่า " font-size
ควรอยู่ที่เท่าไหร่ในวิวพอร์ตแบบกว้าง 850px" คำตอบในกรณีส่วนใหญ่คือจะอยู่ระหว่าง 24px ถึง 34px แต่ตอนนี้มีขนาดเพียง 24px ตาม CSS ของคุณ ซึ่งอาจไม่ใช่สิ่งที่นักออกแบบจินตนาการไว้
ตัวเลือกของคุณ ณ จุดนี้คือการคำนวณขนาดที่ควรจะเป็นและเพิ่มเบรกพอยต์อื่น ที่ง่ายพอ แต่แล้วความละเอียดอื่นๆ ล่ะ? font-size
ควรมีความกว้าง 800px? แล้ว 900px ล่ะ? แล้ว 935px ล่ะ? เห็นได้ชัดว่าผู้ออกแบบไม่ได้จัดเตรียมเลย์เอาต์ที่สมบูรณ์สำหรับทุกความละเอียดที่เป็นไปได้ คุณควรเพิ่มเบรกพอยท์หลายสิบ (หรือหลายร้อย) จุดสำหรับ font-sizes
ต่างๆ ที่นักออกแบบต้องการหรือไม่ แน่นอนไม่
เลย์เอาต์ของคุณปรับขนาดตามความกว้างของวิวพอร์ตได้อย่างลื่นไหลอยู่แล้ว คงจะดีไม่น้อยหากการพิมพ์ของคุณกำหนดขนาดได้ตามเค้าโครงของไหลของคุณ เราจะทำอะไรได้อีกบ้างเพื่อปรับปรุงเรื่องนี้
วิวพอร์ตหน่วยกู้ภัย?
หน่วยวิวพอร์ตเป็นอีกก้าวหนึ่งในทิศทางที่ถูกต้อง สิ่งเหล่านี้ทำให้ข้อความของคุณปรับขนาดได้อย่างลื่นไหลด้วยเลย์เอาต์ของคุณ และการสนับสนุนเบราว์เซอร์ก็ยอดเยี่ยมในทุกวันนี้
แต่ ความสามารถในการใช้งานของหน่วยวิวพอร์ต นั้นขึ้นอยู่ กับการออกแบบสร้างสรรค์ดั้งเดิมสำหรับหน้าเว็บเป็นอย่างมาก เป็นการดีที่จะกำหนด font-size
ของคุณโดยใช้ vw
และเสร็จสิ้น:
h1 { font-size: 2vw; }
แต่จะได้ผลก็ต่อเมื่อบอร์ดศิลปะสร้างสรรค์ของคุณคำนึงถึงสิ่งนี้ นักออกแบบเลือกขนาดข้อความที่เท่ากับ 2% ของความกว้างของอาร์ตบอร์ดแต่ละแผ่นหรือไม่ แน่นอนไม่ มาคำนวณว่าค่า vw
จะต้องเป็นอย่างไรสำหรับเบรกพอยต์แต่ละอันของเรา:
ขนาด 22px
@ 576px
กว้าง = 22 ⁄ 576 *100 = 3.82vw ขนาด 24px
@ 768px
กว้าง = 24 ⁄ 768 *100 = 34px
ขนาด 34px @ 992px
กว้าง = 34 ⁄ 992 *100 = 3.43vw
พวกเขาสนิทกัน แต่ไม่เหมือนกันทั้งหมด ดังนั้น คุณยังคงต้องใช้การสืบค้นสื่อเพื่อเปลี่ยนระหว่างขนาดตัวอักษรและยังคงมีการข้าม และพิจารณาผลข้างเคียงที่แปลกประหลาดนี้:
@ 767px 3.82% ของความกว้างวิวพอร์ตคือ 29px หากวิวพอร์ตกว้างขึ้น 1 พิกเซล ขนาด font-size
จะลดลงเหลือ 24px ทันที ภาพเคลื่อนไหวของวิวพอร์ตที่ถูกปรับขนาดนี้แสดงให้เห็นถึงผลข้างเคียงที่ไม่พึงประสงค์นี้:
การเปลี่ยนแปลงขนาดตัวอักษรที่น่าทึ่งนี้แทบจะไม่ใช่สิ่งที่นักออกแบบคาดคิดไว้เลย แล้วเราจะแก้ปัญหานี้อย่างไร?
สถิติการถดถอยเชิงเส้น?
รอ. อะไร? ใช่ นี่เป็นบทความเกี่ยวกับ CSS แต่คณิตศาสตร์พื้นฐานบางข้อสามารถช่วยแก้ปัญหาของเราได้อย่างดีเยี่ยม
ขั้นแรก ให้พล็อตความละเอียดและขนาดข้อความที่เกี่ยวข้องบนกราฟ:
ที่นี่ คุณสามารถดูพล็อตกระจายของขนาดข้อความที่ระบุของผู้ออกแบบที่ความกว้างของวิวพอร์ตที่กำหนด แกน x คือความกว้างของวิวพอร์ต และแกน y คือ font-size
เห็นเส้นนั้นไหม? ที่เรียกว่า เทรน ด์ไลน์ เป็นวิธีค้นหาค่า font-size
ที่มีการสอดแทรกสำหรับความกว้างของวิวพอร์ตใดๆ โดยอิงจากข้อมูลที่ให้มา
เทรนด์ไลน์คือกุญแจสำคัญของสิ่งนี้
หากคุณสามารถกำหนด font-size
ของคุณตามเทรนด์ไลน์นี้ได้ คุณจะมี h1 ที่ปรับขนาดได้อย่างราบรื่นในทุกความละเอียดที่ ใกล้เคียง กับสิ่งที่นักออกแบบตั้งใจไว้ ก่อนอื่น มาดูคณิตศาสตร์กันก่อน เส้นตรงถูกกำหนดโดยสมการนี้:
- m = ความชัน
- b = จุดตัดแกน y
- x = ความกว้างของวิวพอร์ตปัจจุบัน
- y =
font-size
มีหลายวิธีในการกำหนดความชันและการสกัดกั้น y เมื่อมีหลายค่าที่เกี่ยวข้อง วิธีการทั่วไปคือค่ากำลังสองน้อยที่สุด:
เมื่อคุณเรียกใช้การคำนวณเหล่านั้น คุณจะมีสมการเส้นแนวโน้มของคุณ
ฉันจะใช้สิ่งนี้ใน CSS ได้อย่างไร
โอเค วิชาเลขนี้เริ่มหนักขึ้นมาก เราจะใช้สิ่งนี้จริง ๆ ในการพัฒนาเว็บส่วนหน้าได้อย่างไร คำตอบคือ CSS calc()
! เป็นอีกครั้งที่เทคโนโลยี CSS ที่ค่อนข้างใหม่ซึ่งได้รับการสนับสนุนเป็นอย่างดี
คุณสามารถใช้สมการเส้นแนวโน้มดังนี้:
h1 { font-size: calc({slope}*100vw + {y-intercept}px); }
เมื่อคุณพบความชันและจุดตัด y แล้ว คุณก็แค่เสียบมันเข้าไป!
หมายเหตุ: คุณต้องคูณความชันด้วย 100
เนื่องจากคุณใช้มันเป็นหน่วย vw
ซึ่งเท่ากับ 1/100 ของความกว้างของวิวพอร์ต
สิ่งนี้สามารถทำได้โดยอัตโนมัติหรือไม่?
ฉันย้ายวิธีพอดีกำลังสองน้อยที่สุดลงในฟังก์ชัน Sass ที่ใช้งานง่าย:
/// 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}); }
มันใช้งานได้จริงเหรอ? เปิด CodePen นี้และปรับขนาดหน้าต่างเบราว์เซอร์ของคุณ มันได้ผล! ขนาดตัวอักษรค่อนข้างใกล้เคียงกับการออกแบบดั้งเดิมและปรับขนาดตามเลย์เอาต์ของคุณได้อย่างราบรื่น
ตอนนี้ เป็นที่ยอมรับว่าไม่สมบูรณ์แบบ ค่าต่างๆ ใกล้เคียงกับการออกแบบดั้งเดิมแต่ไม่ตรงกัน ทั้งนี้เนื่องจากเส้นแนวโน้มเชิงเส้นเป็นการ ประมาณ ขนาดของแบบอักษรเฉพาะที่ความกว้างของวิวพอร์ตเฉพาะ นี่คือการสืบทอดของการถดถอยเชิงเส้น มีข้อผิดพลาดอยู่เสมอในผลลัพธ์ของคุณ เป็นการแลกเปลี่ยนระหว่างความเรียบง่ายกับความถูกต้อง นอกจากนี้ โปรดทราบว่ายิ่งขนาดข้อความของคุณมีความหลากหลายมากเท่าใด ข้อผิดพลาดในเทรนด์ไลน์ก็จะยิ่งมีมากขึ้นเท่านั้น
เราสามารถทำได้ดีกว่านี้หรือไม่?
พหุนามกำลังสองน้อยที่สุด
เพื่อให้ได้เส้นแนวโน้มที่แม่นยำยิ่งขึ้น คุณต้องดูหัวข้อขั้นสูง เช่น เส้นแนวโน้มการถดถอยพหุนามที่อาจมีลักษณะดังนี้:
ตอน นี้ เป็นแบบนั้นมากขึ้น! แม่นยำกว่าเส้นตรงของเรามาก สมการถดถอยพหุนามพื้นฐานมีลักษณะดังนี้:
ยิ่งคุณต้องการเส้นโค้งที่แม่นยำมากเท่าไร สมการก็จะยิ่งซับซ้อนมากขึ้นเท่านั้น ขออภัย คุณไม่สามารถทำเช่นนี้ใน CSS calc()
ไม่สามารถทำคณิตศาสตร์ขั้นสูงประเภทนี้ได้ คุณไม่สามารถคำนวณเลขชี้กำลังได้:
font-size: calc(3vw * 3vw); /* This doesn't work in CSS */
ดังนั้น จนกว่า calc()
จะสนับสนุนคณิตศาสตร์ที่ไม่เชิงเส้นประเภทนี้ เราจึงติดอยู่กับ สมการเชิงเส้นเท่านั้น มีอะไรอีกบ้างที่เราสามารถทำได้เพื่อปรับปรุงเรื่องนี้?
เบรกพอยต์และสมการเชิงเส้นพหุคูณ
จะเกิดอะไรขึ้นหากเราคำนวณเพียงเส้นตรงระหว่างเบรกพอยต์แต่ละคู่ บางอย่างเช่นนี้:
ในตัวอย่างนี้ เราจะคำนวณเส้นตรงระหว่าง 22px
ถึง 24px
และอีกเส้นระหว่าง 24px
ถึง 34px
Sass จะมีลักษณะดังนี้:
// SCSS h1 { @media (min-width:576px) { font-size: calc(???); } @media (min-width:768px) { font-size: calc(???); } }
เราสามารถใช้วิธีพอดีกำลังสองน้อยที่สุดสำหรับค่า calc()
เหล่านั้น แต่เนื่องจากเป็นเพียงเส้นตรงระหว่าง 2 จุด คณิตศาสตร์จึงอาจลดความซับซ้อนลงอย่างมาก จำสมการของเส้นตรงได้หรือไม่?
เนื่องจากเรากำลังพูดถึงเพียง 2 จุดในตอนนี้ การหาความชัน (m) และจุดตัดแกน y (b) จึงไม่ใช่เรื่องเล็กน้อย:
นี่คือฟังก์ชัน Sass สำหรับสิ่งนี้:
/// 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}); }
ตอนนี้ เพียงใช้ฟังก์ชันการแก้ไขเชิงเส้นบนเบรกพอยต์หลายจุดใน Sass ของคุณ นอกจากนี้ ให้ใส่ font-sizes
อักษรต่ำสุดและสูงสุด:
// 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; } }
และมันสร้าง CSS นี้:
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; } }
จอกศักดิ์สิทธิ์ของการปรับขนาด CSS?
มาปิดท้ายทั้งหมดนี้ด้วยมิกซ์อิน Sass ที่ดี (สำหรับคนขี้เกียจและมีประสิทธิภาพ!) ฉันกำลังคิดค้นวิธีนี้ 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)); } }
มิกซ์อิน Sass นี้ต้องการฟังก์ชัน Sass บางส่วนในส่วนสำคัญของ Github ต่อไปนี้:
- การแก้ไขเชิงเส้น
- map-sort
- list-sort
- รายการลบ
poly-fluid-sizing()
mixin จะทำการแก้ไขเชิงเส้นบนความกว้างของวิวพอร์ตแต่ละคู่ และกำหนดขนาดต่ำสุดและสูงสุด คุณสามารถนำเข้าสิ่งนี้ไปยังโปรเจ็กต์ Sass และใช้งานได้ง่ายโดยไม่จำเป็นต้องรู้คณิตศาสตร์เบื้องหลัง นี่คือ CodePen สุดท้ายที่ใช้วิธีนี้
หมายเหตุเล็กน้อย
- เห็นได้ชัดว่าวิธีนี้ใช้ไม่ได้เฉพาะกับ
font-size
แต่กับคุณสมบัติหน่วย/ความยาวใดๆ (margin
,padding
เป็นต้น) คุณส่งชื่อคุณสมบัติที่ต้องการลงในมิกซ์อินเป็นสตริง - แมป Sass ของคู่ค่าความกว้างของวิวพอร์ต + ขนาดสามารถส่งผ่าน ในลำดับใดก็ได้ ไปยัง
poly-fluid-sizing()
มันจะจัดเรียงแผนที่โดยอัตโนมัติตามความกว้างของวิวพอร์ตจากต่ำสุดไปสูงสุด ดังนั้นคุณสามารถผ่านแผนที่แบบนี้และมันจะได้ผลดี:
$map: (576px: 22px, 320px: 18px, 992px: 34px, 768px: 24px); @include poly-fluid-sizing('font-size', $map);
- ข้อจำกัดสำหรับวิธีนี้คือคุณไม่สามารถส่งผ่านหน่วยผสมเข้าไปในมิกซ์อินได้ ตัวอย่างเช่น ความกว้าง
3em
@576px
Sass ไม่รู้จริงๆ ว่าต้องทำอะไรทางคณิตศาสตร์ที่นั่น
บทสรุป
นี่คือสิ่งที่ดีที่สุดที่เราสามารถทำได้หรือไม่? Poly Fluid Sizing เป็นจอกศักดิ์สิทธิ์ของการปรับขนาดหน่วยของเหลวใน CSS หรือไม่ อาจจะ. ปัจจุบัน CSS รองรับฟังก์ชันแอนิเมชั่นและจังหวะการเปลี่ยนภาพที่ไม่เป็นเชิงเส้น ดังนั้นอาจมีโอกาสที่ calc()
จะสนับสนุนมันในสักวันหนึ่ง หากเป็นเช่นนั้น การถดถอยพหุนามแบบไม่เป็นเชิงเส้นอาจคุ้มค่าที่จะพิจารณาอีกครั้ง แต่อาจจะไม่… การปรับขนาดเชิงเส้นอาจดีกว่าอยู่แล้ว
ฉันเริ่มสำรวจแนวคิดนี้เมื่อต้นปี 2560 และในที่สุดก็พัฒนาวิธีแก้ปัญหาข้างต้น ตั้งแต่นั้นมา ฉันได้เห็นนักพัฒนาบางคนที่มีแนวคิดคล้ายกันและชิ้นส่วนต่างๆ ของปริศนานี้ ฉันคิดว่าถึงเวลาแล้วที่ฉันจะแบ่งปันวิธีการและวิธีที่ฉันไปถึงที่นั่น หน่วยวิวพอร์ต คำนวณ (). แซส เบรกพอยต์ ไม่มีสิ่งเหล่านี้เป็นของใหม่ เป็นคุณลักษณะของเบราว์เซอร์ทั้งหมดที่มีอยู่เป็นเวลาหลายปี (พร้อมระดับการสนับสนุนที่แตกต่างกัน) ฉันเคยใช้ร่วมกันในลักษณะที่ยังไม่ได้สำรวจอย่างเต็มที่ อย่ากลัวที่จะดูเครื่องมือที่คุณใช้ทุกวันและคิดนอกกรอบว่าคุณจะใช้ประโยชน์จากเครื่องมือเหล่านี้ให้ดีขึ้นได้อย่างไรและพัฒนาชุดทักษะของคุณ