본문 바로가기
CSS

Sass 와 새로운 CSS 기능의 충돌!

by F.E.D 2021. 2. 12.

최근 CSS는 사용자 정의 속성 및 새로운 기능과 같은 새로운 멋진 기능을 많이 추가했습니다.

이러한 것들이 우리의 삶을 훨씬 더 쉽게 만들 수 있지만, 또한 재미있는 방식으로 Sass와 같은 전처리기와 상호 작용할 수 있습니다.

 

새로운 CSS 사용자 속성인 min() 및 max() 함수를 사용해 본 적이 있다면 다른 단위로 작업 할 때 "호환되지 않는 단위 : vh 및 em"과 같은 오류 메시지가 표시 될 수 있습니다.

 

이는 Sass가 자체 min() 함수를 가지고 있고 CSS min() 함수를 무시하기 때문입니다.

또한 Sass는 고정된 관계가없는 단위로 두 값을 사용하여 어떤 종류의 계산도 수행 할 수 없습니다.

min() 내부에서 calc()를 사용하려고하면 오류가 발생합니다.

calc (20em + 7px)와 같은 것을 시도하면 "calc (20em + 7px)는 min에 대한 숫자가 아닙니다."라는 오류가 발생합니다.

 

Sass에는 내장 sepia(), blur(), drop-shadow(), brightness(), contrast(), hue-rotate() 함수가 없지만 자체적으로 grayscale(), invert()가 있습니다. opacity() 함수의 첫 번째 인수는 $color 값입니다.

해당 인수를 찾지 못하기 때문에 opacity, grayscale, invert에서도 오류가 발생합니다.

 

이러한 함수들을 해결하기 위해서는 어떻게 해야할까요?

 

솔루션

트릭은 있습니다.

Sass가 대소문자를 구분하지만 CSS는 그렇지 않다는 점을 기억하는 것입니다.

즉, Min(20em, 50vh)을 작성할 수 있으며 Sass는이를 자체 min() 함수로 인식하지 않습니다.

오류가 발생하지 않으며 의도한대로 작동하는 유효한 CSS입니다.

마찬가지로 HSL() / HSLA() / RGB() / RGBA() 또는 Invert()를 작성하면 이전에 살펴본 문제를 피할 수 있습니다.

그래디언트의 경우 SVG 버전에 더 가깝기 때문에 일반적으로 linear-Gradient() 및 Radial-Gradient()를 선호하지만 적어도 하나의 대문자를 사용하면 잘 작동합니다.

 

 

번외로 Sass와 적절히 Css variable을 혼합한 사용 예제입니다.

- let palettes = {
-		'🦁': '#a728a9 #ce3ec1 #f2408a #ffa26c #ffdb83', 
- 	'🐯': '#7019fb #6b5bfc #4799fc #34d6fd #32fcfe', 
- 	'🦊': '#360b76 #5717b6 #7322e9 #a437f2 #d255fb', 
- 	'🐺': '#006dee #0093fa #00bbee #00eadf #88ffe9', 
- 	'🦝': '#f75759 #ff7f52 #ff9352 #ffba4a #fade73', 
- 	'🐮': '#26a7fb #45c3fd #75d9fd #a0ebff #e7faff', 
- 	'🐭': '#ffb528 #ff8c40 #f86759 #e14b71 #bb3e85', 
- 	'🐱': '#95ffdc #00e1fa #00c1f6 #419fe3 #717dbf', 
- 	'🐼': '#b5ce4f #eed54e #fbb64b #fc7c64 #eb6575', 
- 	'🐻': '#885789 #cf6c84 #f7966f #f6d169 #8bbd69', 
- 	'🐨': '#00aab7 #2889ac #48678f #8478ac #fd98b3', 
- 	'🐰': '#ffca81 #f29e85 #94688c #595678 #4c7ba3', 
- 	'🦔': '#f9ffce #e7cab2 #b8a09f #91ffe2 #00b3ff', 
- 	'🐥': '#92ffe1 #5baeff #fdffcd #ff82a3 #a06eb2'
- }

- for(let p in palettes) {
	- let curr = palettes[p].split(' ');
	- let n = curr.length;
	- let up = Math.ceil(.5*n);
	- let c0 = curr.filter((c, i) => !(i%2));
	- let slist0 = c0.slice(1).map((c, i) => `${c0[i]} ${+((i + 1)*100/up).toFixed(1)}%, ${c} 0`);
	- let dn = Math.floor(.5*n);
	- let c1 = curr.filter((c, i) => (i%2));
	- let slist1 = c1.slice(1).map((c, i) => `${c1[i]} ${+((i + 1)*100/dn).toFixed(1)}%, ${c} 0`);
	- slist1 = `${c1[0]} 0, ${slist1}, ${c1[dn - 1]} ${100 - 50/n}%`;
	.card(style=`--slist0: ${slist0}; --slist1: ${slist1}; --dn: ${dn}`) #{p}
- }

pug로 위와 같이 선언한 뒤에 (보시면 slist0, slist1 등 style이 variable로 선언되어있습니다.) 

@import 'compass/css3';

$w: 13rem;
$f: 1.5;
$h: $f*$w;
$n: 7;
$g: 1rem;

@function dots($n: 2) { // generate dither pixels
	$dots: ();
	
	@for $i from 0 to $n {
		$sx: ($i + 1)*4px;
		
		@for $j from 0 to 2 {
			$sg: pow(-1, $j);
			$dx: if(($i + $j)%2 > 0, 50%, calc(50% + #{.5*$sx}));
			$dy: $sx - 2px + $sg*1px;
			
			@for $k from 0 to 2 {
				$dots: $dots, 
					var(--disc) $dx calc(.5*var(--unit) + #{pow(-1, $k)*$dy})/ #{$sx} var(--unit)
			}
		}
	}
	
	@return $dots
}

body { /* just layout stuff, nothing to do with card backgrounds */
	--h: #{$f*$w};
	box-sizing: border-box;
	display: grid;
	grid-template-columns: repeat(var(--n, #{$n}), var(--w, #{$w}));
	grid-gap: $g;
	place-content: center;
	margin: 0;
	padding: $g;
	min-height: 100vh;
	background: #333;
	
	@for $i from 1 through $n {
		@media (max-width: ($n - $i + 1)*$w + ($n - $i + 2)*$g) {
			@if $i == $n {
				--w: 100%;
				--h: #{$f*100vw};
				--fs: 25vw
			}
			@else { --n: #{$n - $i} }
		}
	}
}

.card {
	display: grid; /* emoji placement */
	place-content: center;
	position: relative;
	width: var(--w); height: var(--h);
	border-radius: 7px;
	box-shadow: 2px 2px 17px #000;
	font-size: var(--fs, 4em); /* emoji size */
	
	&:before, &:after {
		/* use absolutely positioned pseudos covering 
	 	 * entire card to create dithered background */
		position: absolute;
		top: 0; right: 0; bottom: 0; left: 0;
		z-index: -1;
		border-radius: inherit;
		content: ''
	}
	
	&:before {
		/* striped background on the :before (bottom layer) */
		background: Linear-Gradient(var(--slist0))
	}
	
	&:after { /* masking magic on top background layer */
		--n: calc(2*var(--dn) + 1);
		--unit: calc(var(--h)/var(--n));
		--stripe: linear-gradient(transparent 50%, red 0) 0 0/ 100% calc(2*var(--unit));
		--disc: radial-gradient(circle, red .5px, transparent 1px);
		--dots: #{dots()};
		background: Linear-Gradient(transparent calc(50%/var(--n)), var(--slist1), transparent 0);
		-webkit-mask: var(--stripe), var(--dots);
		-webkit-mask-composite: xor; /* non-standard, WebKit */
						mask: var(--stripe), var(--dots);
						mask-composite: exclude /* standard */
	}
}

Linear-Gradient로 해당 변수들을 받아서 처리하고 linear-gradient로 sass 일반 문법을 사용하여 처리합니다.

 

해당 내용들은 참고만 해보시면 좋을 것 같습니다.

 

 

 

See the Pen Simple dithering backgrounds (very little and maintainable code, no images other than CSS gradients, see description!) by YoungMinKim (@oinochoe) on CodePen.

 

 

출처 : css-tricks.com/when-sass-and-new-css-features-collide/

댓글