본문 바로가기

FrontEnd

[번역] min(), max(), clamp() CSS 함수

반응형

원문 : https://ishadeed.com/article/css-min-max-clamp/

 

min(), max(), and clamp() CSS Functions - Ahmad Shadeed

Learn about CSS comparison functions min(), max(), and clamp()

ishadeed.com

브라우저 지원

2020년 8월 이후로 min, max, clamp 함수는 모든 메이저 브라우저에서 지원함.

안타깝게도 ie에서는 못씀

min, max : can i use
clamp : can i use

CSS Compare 함수

CSS 사양(CSS spec)에 따라 여러 값을 비교하고, 사용한 함수를 기반으로 여러 값 중 하나를 나타낸다.

Min() 함수

min() 함수는 하나 이상의 쉼표로 구분된 연산을 포함하며 가장 작은 값을 나타낸다.

보통 최대값을 설정할 때 사용한다.

아래 css는 최대값을 500px로 설정한다.

.element {
  width: min(50%, 500px);
}

뷰포트 너비가 1000px보다 크면 500px이 최솟값으로 사용됨

브라우저는 뷰포트 너비에 따라 두 값 중에서 가장 작은 값(50%, 500px)을 선택한다.
즉, 50%가 500px보다 큰 값으로 계산되면 500px을 사용한다.
그렇지 않으면 500px다 작은 50% 값을 사용한다.
뷰포트 너비가 1000px보다 작으면 뷰포트의 50%가 너비로 사용됨

데모 : Check the interactive demo

Max() 함수

max() 함수는 하나 이상의 쉼표로 구분된 연산 중 가장 큰 값을 나타낸다.
보통 최소값을 설정할 때 사용한다.

아래 css는 최소값을 500px로 설정한다.

.element {
  width: max(50%, 500px);
}

50%이 500px보다 크기 때문에 500px 값은 무시된다.

50%가 500px 미만의 값으로 계산되면 해당 값을 무시하고 500px가 사용된다.
반면 50%가 500px 이상이라면 50%가 너비 값으로 사용된다.

 

데모 : check out the interactive demo

Clamp() 함수

clamp()가 하는 일은 정의된 두 값인 최소값과 최대값 사이의 값을 선택한다.
3개의 매개변수(최소값, 선호값, 최대값)를 사용한다.

.element {
  width: clamp(200px, 50%, 1000px);
}

최소값은 200px, 최대값은 1000px이며, 선호하는 값은 width의 50%이다.

해당 값(50%)은 200px ~ 1000px 사이에만 존재하게 된다.

  • width는 200px 이하로 떨어지지 않는다.
  • 중간(선호) 값은 50%이다.
    • 뷰포트 너비가 400px보다 크고 2000px보다 작은 경우에만 효과가 있다.
  • 너비는 1000px를 넘지 않는다.

데모 : Check the interactive demo


clamp()는 어떻게 계산되는가

Mozilla Developer Network (MDN)은 아래와 같이 설명한다.

.element {
  width: clamp(200px, 50%, 1000px);
  /* Is equivalent to the below */
  width: max(200px, min(50%, 1000px));
}

50%는 뷰포트의 너비에 의해 결정된다.

뷰포트 너비가 1150px 이라고 하면 다음과 같은 단계로 계산된다.

.element {
  width: max(200px, min(50%, 1000px));
  /* Assuming the viewport width is 1150px */
  width: max(200px, min(575px, 1000px));
  /* Resolves to */
  width: max(200px, 575px);
  /* Resolves to */
  width: 575px;
}

컨텍스트가 중요하다.

계산된 값은 컨텍스트에 따라 다르다.
이 컨텍스트는 단위 %, em, rem, vw/vh일 수 있다.
% 값도 요소가 <body>에 직접 적용되면 뷰포트를 기반으로 값을 설정한다.

그렇지 않으면 부모를 기반으로 한다.

 


수학 연산 가능

수학 계산이 가능하므로 calc()를 사용할 필요가 없다.
css 스펙은 다음과 같이 말한다.

각 인수에는 모든 수학 표현식이 허용됩니다.
즉, 내부에 calc()를 중첩할 필요가 없습니다!
적용할 제약 조건이 여러 개인 경우 세 개 이상의 인수를 제공할 수도 있습니다.
.type {
  /* Force the font-size to stay between 12px and 100px */
  font-size: clamp(12px, 10 * (1vw + 1vh) / 2, 100px);
}

CSS 비교 함수가 디자인 방법을 어떻게 바꾸는가

디자이너는 웹 페이지를 디자인할 때 모바일, 데스크톱 크기 둘 다 작업하는 경우가 많으며,

상황에 따라 breakpoint가 더 많을 수 있다.

comparison 함수를 사용하면 디자인 방법이 어떻게 바뀔까?

 

내 생각은 다음과 같다.

breakpoint에서 추천 값으로

첫번째는 현재 작업하는 방식으로 명확한 breakpoint가 있다.
그러나 두 번째는 점진적 디자인을 나타낸다. 중단점이 없다.
중단점이 없는 폰트 사이즈

사용 사례

사이드바와 메인

사이드바와 메인
일반적으로 페이지의 사이드바는 고정되어 있으며 너비는 유동적이다.
뷰포트가 충분히 크면 사이드바의 크기가 더 커지도록 동적으로 만들 수 있다.
이를 위해 max() 함수를 사용하여 최소 너비를 설정한다.
 
아래 예제를 보자.
 
aside의 최소 너비는 150px이다.
뷰포트 너비가 500px(500 * 30% = 150)보다 크면 너비는 30vw가 된다.
.wrapper {
  display: flex;
}

aside {
  flex-basis: max(30vw, 150px);
}

main {
  flex-grow: 1;
}

데모 : Demo

제목 폰트 크기(Headings Font Size)

clamp를 사용한 제목 폰트 크기

clamp()의 훌륭한 사용 사례는 제목이다.
최소 크기가 16px이고 최대 크기가 50px인 제목을 원한다고 가정해보자.

clamp() 함수는 각각 최소값과 최대값 이하 또는 초과하지 않는 중간 값을 제공한다.

.title {
  font-size: clamp(16px, 5vw, 50px);
}

clamp를 사용하여 뷰포트 크기에 가장 적합한 폰트 사이즈를 제공할 수 있다.
min()을 사용하여 최대 글꼴 크기를 설정할 수 있지만,

이 경우 작은 뷰포트에서의 글꼴 크기를 제어할 수 없기에 추천하지 않는다.

.title {
  font-size: min(3vw, 24px); /* Not recommended, bad for accessibility */
}

너비에 따라 커지는 폰트 사이즈

모바일 뷰포트에서는 글꼴 크기가 작다가 갑자기 커진다.
따라서 글자 크기에 min() 함수만 사용하는 것은 좋지 않다.

이전에 언급했듯이 max() 함수 안에 min()을 중첩하여 이는 clamp() 함수를 흉내낼 수 있다.

.title {
  font-size: max(16px, min(10vw, 50px));
}

Twitter에서 논의(discussion)한 결과

font-size의 기본 값으로 10vw만 사용하는 것이 좋지 않다는 의견이 많다는 것을 알게 되었다.
사용자가 브라우저를 확대할 때 접근성 문제가 발생한다.

따라서 아래 값을 추천한다. (prefered value로 (1rem + 5vw))

.title {
  font-size: clamp(16px, (1rem + 5vw), 50px);
}

Decorative Headings(장식 제목)

흐릿한 Latest articles라는 섹션 타이틀은 뷰포트 크기에 따라 크기가 조절되는 장식용 텍스트다.

CSS 뷰포트 단위와 함께 max 함수를 사용하여 폰트 사이즈의 최소값을 설정할 수 있다.

.section-title:before {
  content: attr(data-test);
  font-size: max(13vw, 50px);
}
데모 : Demo

Smoothing Gradients

CSS에서 그래디언트를 사용하는 경우, 모바일에서는 색상 간 전환을 좀 더 부드럽게 할 필요가 있다.
.element {
  background: linear-gradient(135deg, #2c3e50, #2c3e50 60%, #3498db);
}

모바일에서의 색상 간 전환이 급격한 것이 봉니다.

모바일에서는 색상 구분선이 보인다. 이는 좋지 않다.

이 문제를 미디어 쿼리로도 해결할 수 있다.

@media (max-width: 700px) {
  .element {
    background: linear-gradient(135deg, #2c3e50, #2c3e50 25%, #3498db);
  }
}

하지만 min 함수를 사용하면 좀 더 다이나믹하게 표현할 수 있다.

.element {
  background: linear-gradient(135deg, #2c3e50, #2c3e50 min(20vw, 60%), #3498db);
}

부드러워진 그라디언트

데모 : Demo

Transparent Gradient

사진 위에 텍스트를 배치해야 하는 경우 텍스트를 읽을 수 있도록 사진 아래에 그라데이션이 있어야 한다.
이전 예와 마찬가지로 그래디언트 크기는 작은 뷰포트와 큰 뷰포트 간에 동작이 좀 달라야 한다.

데스크탑과 모바일 그라디언트

.element {
  background: linear-gradient(to top, #000 0, transparent max(20%, 20vw));
}

약간의 개선을 적용하여 모바일에서 좀 더 적절하게 보이도록 할 수 있다.
max() 함수를 사용하여 최소값을 설정하는 것이다.

그래디언트의 크기가 데스크톱에서 상위 요소 크기의 50%이면, 모바일에서는 30% 정도가 적절하다.

 

데모 : Demo

Dynamic Margin (동적 마진)

동적 마진

CSS 뷰포트 단위를 사용하여 디자인 요소 사이에 동적 마진을 적용할 수 있다.
하지만 사용자가 세로 높이가 긴 회전된 화면에서 디자인을 볼 수 있으므로 항상 좋은 솔루션이 아닐 수 있다.
다음은 미디어 쿼리로 이를 수행하는 방법이다.
h1,
h2,
h3,
h4,
h5 {
  margin: 7vh 0 1.05rem;
}

@media (max-height: 2000px) {
  h1,
  h2,
  h3,
  h4,
  h5 {
    margin: 2.75rem 0 1.05rem;
  }
}
 
이를 단 한줄로 고칠 수 있다.
h1,
h2,
h3,
h4,
h5 {
  margin: min(7vh, 2.75rem) 0 1.05rem;
}

 

min()을 사용하여 2.75rem의 마진 최대값을 설정했다.
데모 : Demo

Container Width (컨테이너 너비)

부모 너비의 80%를 차지하는 컨테이너가 있고 너비가 780px를 초과하지 않아야 하는 경우 css를 어떻게 적용할까?

다음과 같은 방법이 있다.

.container {
  max-width: 780px;
  width: 80%;
}

이를 아래와 같이 고칠 수 있다.

.container {
  max-width: min(80%, 780px);
}

데모 : Demo 


Section Vertical Padding(섹션 수직 패딩)

clamp 함수는 hero 영역의 최소, 최대 패딩 설정에 최적이다.

.hero {
  padding: clamp(2rem, 10vmax, 10rem) 1rem;
}

데모 : Demo 

Border And Shadow

일부 디자인 사례의 경우 테두리 너비와 반경이 큰 요소가 모바일에서는 더 작아야 한다.
clamp()를 사용하여 뷰포트 너비에 따라 동적으로 만들 수 있다.

.element {
  box-shadow: 0 3px 10px 0 red;
  border: min(1vw, 10px) solid #468eef;
  border-radius: clamp(7px, 2vw, 20px);
  box-shadow: 0 3px clamp(5px, 4vw, 50px) 0 rgba(0, 0, 0, 0.2);
}

데모 : Demo

 

Use Case - Border, Border Radius, Shadow

...

codepen.io

Grid Gap

모바일에서는 그리드 간격을 더 작게 만들 수 있다.

.wrapper {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-gap: clamp(1rem, 2vw, 24px);
}

딥 다이브 : here

데모 : Demo


CSS Comparision 함수는 단위있는 값을 사용해야 함.

이런거 안됨

.element {
  width: clamp(0, 10vmax, 10rem);
}

레거시 브라우저 지원

1. fallback 직접 작성

.hero {
  padding: 4rem 1rem;
  padding: clamp(2rem, 10vmax, 10rem) 1rem;
}

 

 

2. @supports 사용

.hero {
  /* Default, for non-supporting browsers */
  padding: 4rem 1rem;
}

@supports (width: min(10px, 5vw)) {
  /* An enhancement for supporting browsers */
  .hero {
    padding: clamp(2rem, 10vmax, 10rem) 1rem;
  }
}

비교 함수를 지원하는 모든 브라우저는 이 솔루션을 지원함


접근성을 고려할 것

CSS 비교 함수는 보다 동적인 웹 페이지를 만드는 새로운 방법을 제공하지만 사용 방법에 더 주의해야 함.
예를 들어 min()을 사용하여 글꼴 크기를 설정하는 것은 모바일에서 너무 작기 떄문에 좋지 않음.
사용자 경험에 중요한 항목은 최대값과 최소값을 둘 다 설정해야 함

 

반응형