며칠 전 아래의 아티클을 읽었다. 잘못된 css 코드의 몇 가지 유형에 대한 글이었다. css는 정말 어렵다. 맨처음 프론트엔드의 세계에 첫 발을 들여놓았을 때는 자바스크립트의 벽을 느끼지만 시간이 조금만 지나면 오히려 css가 통곡의 벽이라는 걸 느끼게 된다. (통대 입시를 준비할 때는 AB 통역, 즉 모국어를 듣고 외국어로 발화하는 통역이 어렵게 느껴지지만 필드에 나오면 BA 통역이 더 어렵다는 걸 느끼는 것과 똑같다.)
위의 아티클에서 언급한 유형 중에 매직 넘버와 절대값(absolute value)에 대해서 나름의 생각을 짧게 얘기해보고자 한다.
1. 매직 넘버 (magic number)
본문에서 매직 넘버는 '반드시 그렇게만 작동하는' 값이라고 했는데, 기본적으로 다른 사람이 봤을 때 어디서 온 숫자인지 알기 힘든 값이라고 생각하면 좋을 것 같다. 이 포스팅에서 매직 넘버에 대해서 간단하게 언급하고 싶은 이유는 매직 넘버가 꼭 css만의 문제는 아니기 때문이다. 아래 코드는 특정 키워드 입력시 기존에 있는 키워드를 드랍다운으로 보여주는 컴포넌트를 만들기 위한 초안이다.
function CreateCategory() {
// TODO: 서버 api get 요청으로 카테고리 배열 데이터 받아오기
const categories: Array<string> = [
'배드민턴',
'축구',
'풋살',
'농구',
'배구',
'골프',
'볼링',
'테니스',
'하키',
'당구'
];
//* hasText: input값 유무 확인
//* inputValue: input값의 상태 확인
//* options: input값을 포함하는 autocomplete 추천 항목 리스트 확인
//* currentOption: 선택한 option을 index처럼 관리
const [hasText, setHasText] = useState(false);
const [inputValue, setInputValue] = useState('');
const [options, setOptions] = useState(categories);
const [currentOption, setCurrentOption] = useState(-1);
const input = useRef(null);
useEffect(() => {
if (inputValue === '') {
setHasText(false);
}
}, [inputValue]);
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
setHasText(true);
setOptions(categories.filter((item) => item.startsWith(e.target.value)));
};
const handleDropDownClick: HandleDropDownClick = (clickedOption) => {
setInputValue(clickedOption);
setOptions(categories.filter((item) => item.startsWith(clickedOption)));
};
const handleKeyUp = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (hasText) {
if (e.key === 'ArrowUp' && currentOption > -1) {
setCurrentOption((cur) => cur - 1);
} else if (e.key === 'ArrowDown' && currentOption < options.length - 1) {
setCurrentOption((cur) => cur + 1);
} else if (e.key === 'Enter') {
handleDropDownClick(options[currentOption]);
setCurrentOption(-1);
}
}
};
return (
<div>
<S_InputContainer hasText={hasText}>
<label htmlFor='categoryName'>어떤 소모임을 만드실 건가요? *</label>
<p>소모임 종류는 한번 입력하시면 변경할 수 없습니다.</p>
<input
id='categoryName'
type='text'
value={inputValue}
onKeyUp={handleKeyUp}
onChange={handleInputChange}
ref={input}
/>
</S_InputContainer>
{hasText && (
<DropDown
options={options}
handleComboBox={handleDropDownClick}
currentOption={currentOption}
/>
)}
</div>
);
}
여기에서 어떤 옵션을 선택했는지를 알기 위한 상태값을 관리하기 위해 const [currentOption, setCurrentOption] = useState<number>(-1); 과 같이 코드를 작성했다. 인덱스 초기값을 -1로 설정했는데, 이러한 -1이 바로 매직 넘버다. 다른 사람이 추후에 인덱스 -1의 의미를 잘못 해석할 수 있기 때문에 유지보수 중 문제가 생길 수 있는 것이다. === -1 처럼 매직 넘버 자체를 그대로 비교하는 경우가 생길 수도 있다. 이 경우에는 아래와 같이 상수에 담아 사용하면 이러한 문제를 피할 수 있다.
const INITIAL_OPTION_INDEX = -1;
const [currentOption, setCurrentOption] = useState(INITIAL_OPTION_INDEX);
2. 절대값과 상대값
css로 다시 되돌아오자. 반응형 디자인을 신경 쓴다면 절대값은 절대 피해야 한다. 상대값을 쓸 때에는 부모 객체와의 상대적 크기를 지정하는 퍼센테이지와 css 상대 길이 단위인 em과 rem 중 한 가지 방식을 주로 사용한다. (물론 vh와 vw도 있다.) em과 rem은 둘 다 font-size를 기준으로 하는데, em은 부모의 폰트 사이즈, rem은 root의 폰트 사이즈를 기준으로 한다는 게 차이점이다.
브라우저에서 루트는 <html> 요소이고, 크롬 브라우저 기준 별도의 사용자 지정 설정이 없는 경우 브라우저 내장 폰트 사이트는 16px이다. 그렇기 때문에 1rem = 16px, 2rem = 32px 등이 된다. 루트 요소의 font-size: 16px 을 변경하고 싶다면 다음과 같이 css 코드를 작성하면 된다.
html {
font-size: 12px
}
하지만 css reset 이나 css normalize 를 위해서 보통은 html 태그 선택자보다 다음과 같은 :root 선택자를 더 자주 사용하는 걸 볼 수 있다.
:root {
font-size: 12px
}
pseudo 클래스인 :root 는 html 선택자와 똑같지만 명시도(specificity)가 더 높다. (출처: mdn) 실제 프로젝트에서는 :root 에서 폰트 사이즈를 변경하는 것보다는 컬러 팔레트 등 css 전역 변수를 설정하는 경우가 많다.
:root {
--white: #FFF;
--black: #000;
--gray100: #F1F3F6;
--gray200: #CACFD9;
--gray300: #A1A9B4;
--gray400: #788290;
--gray500: #3D4755;
--gray600: #272E3A;
--blue100: #E3F0FF;
--blue200: #90C2FF;
--blue300: #377CFB;
--red100: #F04452;
--green100: #04D182;
--kakao-main-theme: #FEE500;
--kakao-hover-theme: #FADA0A;
--naver-main-theme: #19CE60;
--naver-hover-theme: #1BC15C;
}
+) 한 가지 더 : 리액트에서 내장 css normalize 를 사용하는 방법
index.css 파일의 최상단에 다음과 같이 @import-normalize 를 불러와주면 된다. 간단하죠?
@import-normalize;
create-react-app 공식문서에도 나와있다시피 짜글짜글한 밑줄과 함께 "Unknown at rule @import-normalize css(unknownAtRules)" 라는 경고가 뜰 수 있는데, 이 경우에는 다음과 같은 작업을 해주면 된다.
1) 프로젝트 루트 폴더에 .vscode 폴더 생성
2) .vscode 폴더 안에 settings.json 파일 생성
3) settings.json 파일에 다음과 같이 css.lint.unknownAtRules 설정을 추가
{
"css.lint.unknownAtRules": "ignore"
}
css reset 이나 css normalize 라이브러리들이 많이 있지만 내가 원하는 리셋이 되지 않을 때가 종종 있어서 개인적으로는 커스텀 reset 코드를 선호하는 편이다.
'배워서 남 주자' 카테고리의 다른 글
프로그래머스 Lv.1 | 기사단원의 무기 (JavaScript) (0) | 2023.05.21 |
---|---|
[styled-components] css 스타일 코드를 분리해서 작성하기 (0) | 2023.05.20 |
모바일 기기에서 localhost 접속하는 방법 (2) | 2023.05.15 |
프로그래머스 Lv.1 | 과일장수 (JavaScript) (1) | 2023.05.12 |
[styled-components] 공통 UI 컴포넌트 및 theme 기능 (2) | 2023.04.06 |