원문 : https://ishadeed.com/article/css-min-max-clamp/
브라우저 지원
2020년 8월 이후로 min, max, clamp 함수는 모든 메이저 브라우저에서 지원함.
안타깝게도 ie에서는 못씀
CSS Compare 함수
CSS 사양(CSS spec)에 따라 여러 값을 비교하고, 사용한 함수를 기반으로 여러 값 중 하나를 나타낸다.
Min() 함수
min() 함수는 하나 이상의 쉼표로 구분된 연산을 포함하며 가장 작은 값을 나타낸다.
보통 최대값을 설정할 때 사용한다.
아래 css는 최대값을 500px로 설정한다.
.element {
width: min(50%, 500px);
}
데모 : Check the interactive demo
Max() 함수
max() 함수는 하나 이상의 쉼표로 구분된 연산 중 가장 큰 값을 나타낸다.
보통 최소값을 설정할 때 사용한다.
아래 css는 최소값을 500px로 설정한다.
.element {
width: max(50%, 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 함수를 사용하면 디자인 방법이 어떻게 바뀔까?
내 생각은 다음과 같다.
사용 사례
사이드바와 메인
.wrapper {
display: flex;
}
aside {
flex-basis: max(30vw, 150px);
}
main {
flex-grow: 1;
}
데모 : Demo
제목 폰트 크기(Headings Font Size)
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);
}
Smoothing Gradients
.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 (동적 마진)
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;
}
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
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;
}
}
비교 함수를 지원하는 모든 브라우저는 이 솔루션을 지원함
접근성을 고려할 것
'FrontEnd' 카테고리의 다른 글
리액트 쿼리와 비교한 RTK Query와 Mutation(뮤테이션), 캐싱 동작 (0) | 2023.03.31 |
---|---|
[번역] Mobile First Design vs Desktop First Design (0) | 2023.03.29 |
[JS] 한글을 2byte로 한 줄 길이 제한 및 줄바꿈 코드 (0) | 2023.03.24 |
[Vite, Vitest, Javascript] Vanilla JS로 TDD with Vitest (0) | 2023.03.23 |
[번역] React TDD 기초 (0) | 2023.03.21 |