CSS Poly Fluid Sizing을 사용한 Fluid Responsive Typography
게시 됨: 2022-03-10이 기사에서 우리는 그것을 다른 수준으로 가져갈 것입니다. 잘 지원되는 브라우저 기능과 몇 가지 기본 대수를 사용하여 여러 중단점과 미리 정의된 글꼴 크기에 걸쳐 확장 가능하고 유동적인 타이포그래피를 만드는 방법 을 조사할 것입니다. 가장 좋은 점은 Sass를 사용하여 모든 것을 자동화할 수 있다는 것입니다.
SmashingMag에 대한 추가 정보:
- vh 및 vw 단위를 사용한 진정한 유동성 타이포그래피
- 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
를 제공된 중단점에서 디자이너가 지정한 것으로만 제한하고 있습니다. "850px 너비의 뷰포트에서 font-size
는 어떻게 되어야 합니까?"라고 묻는 경우 디자이너는 어떻게 대답할까요? 대부분의 경우 대답은 24px에서 34px 사이입니다. 그러나 지금은 CSS에 따라 24픽셀에 불과하며, 이는 아마도 디자이너가 구상한 것이 아닐 것입니다.
이 시점에서 당신의 선택은 그 크기가 어떠해야 하는지를 계산하고 또 다른 중단점을 추가하는 것입니다. 충분히 쉽습니다. 그러나 다른 모든 결의안은 어떻습니까? font-size
는 너비가 800픽셀이어야 합니까? 900px는 어떻습니까? 935px는 어떻습니까? 분명히 디자이너는 가능한 모든 단일 해상도에 대한 전체 레이아웃을 제공하지 않을 것입니다. 그렇다고 해도 디자이너가 원하는 다양한 font-sizes
에 대해 수십(또는 수백) 개의 중단점을 추가해야 합니까? 당연히 아니지.
레이아웃은 이미 뷰포트의 너비에 따라 유동적으로 조정됩니다. 타이포그래피가 유동적인 레이아웃으로 예측 가능하게 확장된다면 좋지 않을까요? 이를 개선하기 위해 우리가 할 수 있는 다른 일은 무엇입니까?
구조를 위한 뷰포트 유닛?
뷰포트 단위는 올바른 방향으로 나아가는 또 다른 단계입니다. 레이아웃에 따라 텍스트의 크기를 유연하게 조정할 수 있습니다. 그리고 브라우저 지원은 요즘 훌륭합니다.
그러나 뷰포트 단위의 실행 가능성은 웹 페이지의 독창적인 디자인에 크게 의존 합니다. vw
를 사용하여 font-size
를 설정하고 완료하는 것이 좋습니다.
h1 { font-size: 2vw; }
그러나 이것은 크리에이티브 아트보드에서 이를 고려하는 경우에만 작동합니다. 디자이너가 각 아트보드 너비의 정확히 2%인 텍스트 크기를 선택했습니까? 당연히 아니지. 각 중단점에 대해 필요한 vw
값을 계산해 보겠습니다.
22 22px
크기 @ 576픽셀 너비 = 22 ⁄ 576 *100 = 576px
24픽셀 크기 @ 768 768px
너비 = 24 ⁄ 768 *100 = 24px
34 34px
크기 @ 992 992px
너비 = 34 ⁄ 0 992 *
그들은 가깝지만 모두 같지는 않습니다. 따라서 텍스트 크기 간에 전환하려면 미디어 쿼리를 사용해야 하며 여전히 점프가 있습니다. 그리고 이 이상한 부작용을 고려하십시오.
@ 767px, 뷰포트 너비의 3.82%는 29px입니다. 뷰포트가 1픽셀 더 넓으면 font-size
갑자기 다시 24픽셀로 떨어집니다 . 크기가 조정되는 뷰포트의 이 애니메이션은 다음과 같은 바람직하지 않은 부작용을 보여줍니다.
글꼴 크기의 이러한 극적인 변화는 거의 확실히 디자이너가 구상한 것과 다릅니다. 그렇다면 이 문제를 어떻게 해결할 수 있을까요?
통계적 선형 회귀?
기다리다. 뭐라고 요? 예, 이것은 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절편을 찾으면 연결하기만 하면 됩니다!
참고: 기울기를 뷰포트 너비의 1/100인 vw
단위로 사용하기 때문에 기울기에 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개의 점에 대해 이야기하고 있기 때문에 기울기(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 mixin으로 마무리하겠습니다(게으르고 효율적인 경우를 위해!). 이 방법을 만들고 있습니다. 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 믹스인에는 다음 Github 요점에서 몇 가지 Sass 함수가 필요합니다.
- 선형 보간
- 지도 정렬
- 목록 정렬
- 목록 제거
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);
- 이 방법의 제한 사항은 혼합 단위를 mixin에 전달할 수 없다는 것입니다. 예를 들어
3em
@576px
너비입니다. Sass는 그곳에서 수학적으로 무엇을 해야 할지 정말 모를 것입니다.
결론
이것이 우리가 할 수 있는 최선입니까? Poly Fluid Sizing은 CSS에서 유체 단위 크기 조정의 성배입니까? 아마도. CSS는 현재 비선형 애니메이션 및 전환 타이밍 기능을 지원하므로 calc()
도 언젠가는 지원할 가능성이 있습니다. 그런 일이 발생하면 비선형 다항식 회귀를 다시 살펴볼 가치가 있습니다. 하지만 그렇지 않을 수도 있습니다. 어쨌든 선형 확장이 더 우수할 수 있습니다.
저는 2017년 초에 이 아이디어를 탐구하기 시작했고 결국 위의 솔루션을 개발했습니다. 그 이후로 저는 몇 명의 개발자가 이 퍼즐의 비슷한 아이디어와 다른 조각을 생각해 내는 것을 보았습니다. 제 방법과 거기에 도달한 방법을 공유해야 할 때라고 생각했습니다. 뷰포트 단위. 계산(). 사스. 중단점. 이 중 어느 것도 새로운 것이 아닙니다. 이들은 모두 수년간 존재해 온 브라우저 기능입니다(다양한 지원 수준 포함). 나는 아직 완전히 탐구되지 않은 방식으로 그것들을 함께 사용했을 뿐입니다. 매일 사용하는 도구를 살펴보고 도구를 더 잘 활용하고 기술을 향상시킬 수 있는 방법에 대해 즉시 생각하는 것을 두려워하지 마십시오.