이 프로젝트는 input태그에 사용자가 입력한 값을 다른 요소가 접근할 수 있도록 하는 것이 핵심이었습니다.
생각보다 금방 끝날 것 같으니, 구현을 다 마친 다음에는 리팩토링을 함께 진행해보도록 하죠!😆
PR: https://github.com/SeungrokYoon/25-vanilla-javascript-projects/pull/17
site: https://animated-pony-97da24.netlify.app/
카드 디자인을 보고 크게 위에서 아래로 세 부분으로 나누면 좋겠다는 생각을 했습니다.
label
과 input
, 그리고 제출버튼이 있는 middleinput
의 값이 출력되는 bottom이것 설계를 바탕으로 아래와같이 마크업구조와 스타일을 잡았습니다. 추가적인 스타일링은 기능구현 이후에 하도록 할게요.
<body>
<div id="root">
<div class="container">
<div class="card">
<div class="card-top">
<h3>Pass the message</h3>
</div>
<hr />
<div class="card-middle">
<label for="message-input">Enter a message</label>
<div>
<button>icon</button><input id="message-input" type="text" />
</div>
<button id="submit">Submit</button>
</div>
<div class="card-bottom">
<p id="output-message"></p>
</div>
</div>
</div>
</div>
<script type="module" src="main.js"></script>
</body>
기능구현의 핵심은 버튼의 클릭이벤트
, keydown 이벤트
를 활용해서 input의 값을 카드컴포넌트 하단의 p
태그에 업데이트하는 작업이었습니다.
https://developer.mozilla.org/en-US/docs/Web/API/Element/keydown_event
기능구현이 완료된 모습은 다음과 같습니다.
버튼을 클릭할 때, 엔터키를 누를 때 동일한 로직이 반복되는 것 같아
submitMessage
함수로 값을 주는 쪽과 받는 쪽을인자로 받을 수 있도록 개선했습니다.
const inputEl = document.getElementById('message-input');
const submitBtn = document.getElementById('submit');
const outputMessageEl = document.getElementById('output-message');
function submitMessage({ start, destination }) {
const nextText = start.value;
start.value = '';
const currentDestinationText = destination.innerHTML;
const isNewTextNotEmpty = nextText.length;
const shouldUpdate = isNewTextNotEmpty && currentDestinationText !== nextText;
shouldUpdate ? (destination.innerHTML = nextText) : '';
if (!isNewTextNotEmpty) alert('The message is empty!');
}
submitBtn.addEventListener('click', (e) => {
submitMessage({ start: inputEl, destination: outputMessageEl });
});
inputEl.addEventListener('keydown', (e) => {
if (e.code === 'Enter') {
submitMessage({ start: e.target, destination: outputMessageEl });
}
});
이메일 아이콘을 인풋 태그 옆에 넣을 예정입니다.
Google Material Icon은 폰트더라구요. 그래서 만약 아이콘을 기본 형태가 아닌 다른 형태 (outlined, two tone, round, sharp) 로 사용하고 싶다면, 구글 폰트 API를 사용하는 방식으로 스타일에 맞는 폰트를 불러와야서 HTML에 추가해줘야합니다.
이렇게요!
<link
href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone|Material+Icons+Round|Material+Icons+Sharp"
rel="stylesheet"
/>
이렇게 하고 나면, 다운로드받은 폰트에 따라 특정 클래스이름(material-icon, material-icon-outlined, 등등)에 자동으로 스타일이 적용되게 됩니다.
아이콘을 사용할 때는 아래와 같이 클래스 이름
+ 클래스 요소 내부에 아이콘 이름
을 명시해 사용해주시면 되겠어요!
<span class="material-icons-outlined">
home
</span>
내가 사용하는 색상코드에 rgba처럼 불투명도를 주고 싶었습니다.
그렇지만 hexcode를 매번 rga로 변형하고, 거기에 alpha코드를 부여하는 것은 너무 불편해요.
그래서 검색해보았습니다. 투명도 수치를 4bit의 hexadecimal(16진수)로 표현해서 추가할 수가 있었습니다.
https://gist.github.com/lopspower/03fb1cc0ac9f32ef38f4
만약 이 프로젝트를 리액트로 제작했다면, 저는 카드의 레이아웃을 별도로 만들어, top, middle, bottom에 각각 children을 전달했을 것 같습니다.
//상상해본 리액트 컴포넌트 예시1
<MessageCardLayout
top={<h3>Pass the message</h3>}
middle={<>
<label for="message-input">Enter a message</label>
<div>
<button>icon</button><input id="message-input" type="text" />
</div>
<button id="submit">Submit</button>} bottom={}/>
</>
bottom={<p id="output-message"></p>}
/>
만약 top에는 h3태그만 사용해야한다처럼 디자인이 확정되었다면, props로 텍스트만 전달해도 되겠네요.
또한 인풋태그와 아이콘은 하나의 컴포넌트로 추상화했을 것 같아요.
//상상해본 리액트 컴포넌트 예시2
<MessageCardLayout
top={"Pass the message"}
middle={<>
<InputWithIcon src={} withIcon={true}/>
<button id="submit">Submit</button>} bottom={}/>
</>
bottom={<p id="output-message"></p>}
/>
생각해보면 제출버튼은 인풋과 매우 밀접한 관련이 있는데요, 이것은 어떻게 해야할까요?
역시 디테일한 스타일링은 집중력이 요구됩니다.
아이콘이 버튼의 가운데정렬이 되지 않아서 고생했어요.
구글 아이콘은 <span>
로 이루어져있어서 span태그에 vertical-align:middle
을 적용해 세로가운데정렬을 시켜주었습니다.
input요소에 overflow:hidden을 주지 않으면, input요소가 입력받은 값들이 다 표시가 되면서 컨테이너 밖으로 삐져나올 수 있습니다.
flex:1
을 주어도 일정 부분 미만으로 줄어들지 않는 기이한 현상을 발견할 수도 있으니 앞으로 주의해야겠습니다.
overflow:hidden
이 없을 때overflow:hidden
이 주어졌을 때프로젝트를 배포 후에 Iphone 11 Pro
기기에서 크롬에 접속하여 내 프로젝트를 확인해보았다. 그런데 웬걸? 버튼 텍스트 색이 퍼렁색이 되어있었다! 😅
개발하면서 개발자도구로 모바일 기기에 대한 스타일 확인을 하면서 작업을 했는데 이 경우는 발견하지 못했다.
검색을 해보니 나와 비슷한 일을 겪은 개발자들이 있었다.
https://developer.apple.com/forums/thread/690529
그래서 나도 모바일 브라우저의 개발자도구를 열기위해서 노트북에 아이폰을 연결하고 사파리에서 문제가 된 페이지에 대한 개발자도구로 확인했더니 ...
두둥! color: -apple-system-blue
? 가 button 하위요소에 적용이 되어 있었습니다. 이 녀석이 IOS 기기의 기본 색상을 반영하는 녀석이었나봅니다.
공교롭게도 Material Icon에서는 color를 따로 지정하고 있지 않았습니다.
그러니 button 태그에 명시적으로 color값을 주면 해결이 되겠군요. color속성은 상속이 되니까요.
결과는~
다행히 검은색으로 아이콘과 버튼텍스트가 출력이됩니다 야호~^^
이런 이슈가 있었다니... 처음알게되었어요. 스타일링할 때 주의해야겠군요.
아주 유익한 내용이네요!