(2023.06.29)
먼저 기본 마크업과 레이아웃을 잡아주었습니다. 결과는 아래와 같습니다. 버튼 그룹은 버튼이 2개만 있어서 css의 :nth-child(1)
가상 클래스로 Generate 버튼 우측의 마진값을 주었습니다. 버튼 두 개 사이의 간격을 주는데 display:flex
를 사용하는것은 비효율적이라 생각했기 때문입니다. 버튼이 조금 더 많았다면 display:flex;, gap:10px;
속성을 사용했을 것 같습니다.
기본 마크업이 끝난 직후 모습
추가적인 스타일링은 핵심 기능이 완료되고 나서 조정할 예정입니다. 그러면 어떤 기능이 필요한지 나열해볼까요?
45deg
로 고정이다먼저 랜덤한 hex color 값을 생성하는 함수를 작성했습니다. 코드상으론 getrandomHexText()
입니다.
Math.random 에 2의 16제곱수를 곱하여 0과 2^16 사이의 랜덤한 수를 생성한 후, 정수로 바꿔줍니다.
이후, toString 매서드를 통해 10진수의 정수를 16진수의 텍스트로 변환해주고, 빈 자리에는 0을 채워줌으로써 6자리 hexcolor 코드가 나오게 됩니다.
색상코드 생성 테스트
이후에는 Generate 버튼에 이벤트 리스너를 추가하면서, 이벤트 핸들러 함수에서 배경 색상과 텍스트가 변경되도록 하였습니다. 이벤트 핸들러 함수에서 배경 색상 변경과, 텍스트 변경 로직을 별도의 함수로 추상화하여 가독성을 높였습니다.
브라우저 API중에는 클립보드와 상호작용할 수 있는 navigator.clipboard API가 존재합니다.
해당 API에는 writeText() 매서드가 있어 이를 활용하면 원하는 기능을 구현할 수 있을 것 같아 보입니다.
그래서 버튼에 클릭 이벤트가 발생할 시에, 클립보드로 문자열을 복사하는 로직을 작성해 보았습니다.
function copyToClipboard() {
const text = hexText.textContent;
navigator.clipboard
.writeText(text)
.then((r) => alert('Copied!'))
.catch((e) => alert('Try again'));
}
copyBtn.addEventListener('click', copyToClipboard);
어라? 그런데 이상합니다. 얼핏 보기에는 맞는 코드 같아 보이는데, then 구문에도, catch 구문에도 아무런 응답이 없습니다. 저는 어떤 잘못을 한 것일까요?
이 과정은 조금 길어서 따로 정리했어요. 아래 링크를 참고해주시면 감사하겠습니다!
링크 - Live Server를 HTTPS 프로토콜 방식으로 사용해보자!
기능구현을 마친 JS 파일은 아래와 같습니다.
const background = document.querySelector('.background');
const hexText = document.querySelector('.hex-text');
const btnContainer = document.querySelector('.btn-container');
const generateBtn = document.querySelector('#generate-btn');
const copyBtn = document.querySelector('#copy-btn');
function genLinearGradientValue(degree, colorFrom, colorTo) {
return `linear-gradient(${degree}deg, ${colorFrom}, ${colorTo})`;
}
function init() {
const initialColor = '#000000';
const styleText = genLinearGradientValue(45, initialColor, initialColor);
background.style.background = styleText;
hexText.textContent = `background: ${styleText}`;
}
function getRandomHexText() {
const randomHex =
'#' +
parseInt(Math.random() * 2 ** 16)
.toString(16)
.padStart(6, 0);
return randomHex;
}
function updateBgColor(colorFrom, colorTo) {
background.style.background = genLinearGradientValue(45, colorFrom, colorTo);
}
function updateHexText(colorFrom, colorTo) {
const text = `background: ${genLinearGradientValue(45, colorFrom, colorTo)}`;
hexText.textContent = text;
}
function changeBgToRandomHexColor() {
const hex1 = getRandomHexText();
const hex2 = getRandomHexText();
updateBgColor(hex1, hex2);
updateHexText(hex1, hex2);
}
function copyToClipboard() {
const text = hexText.textContent;
navigator.clipboard
.writeText(text)
.then((r) => alert('Copied!'))
.catch((e) => alert('Try again'));
}
init();
generateBtn.addEventListener('click', changeBgToRandomHexColor);
copyBtn.addEventListener('click', copyToClipboard);
https://css-tricks.com/html-vs-body-in-css/
body태그에 바로 스타일링을 하는것은 물론 가능합니다. 그렇지만 이것이 반드시 좋다라고는 할 수 없다는 생각이 들었습니다. 특히 SPA 방식의 프로덕트라면 body태그에 직접적으로 스타일을 거는 것은 body 하위의 요소들의 스타일에 제약을 걸 수 있다는 생각이 들었어요.
참고: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
많이 사용하는 매서드이지만, 이벤트 핸들러 함수로서 두 번째 인자로 올 수 있는 값인 자바스크립트 함수 형태별 차이점을 제대로 모르고 사용해왔었습니다. 때로는 기분에 따라, 때로는 손이 가는 대로 콜백함수의 형태를 일반함수, 익명함수, 화살표함수로 분별없이 사용했었는데, 이번에는 각 콜백형태의 특징을 제대로 짚고 넘어가야겠다 생각이 들어 기록해봅니다.
EventTarget
인터페이스의 매서드인 addEventListener()
는 이벤트가 타겟(Element, Document, Window, 또는 event를 지원하는 모든 객체)으로 전달이 되었을 때 호출되는 함수를 설정할 때 사용됩니다. addEventListener()
을 통해 Event Listener
를 타겟에 등록
하게 되는 것입니다. 그렇게 함으로써 해당 타겟은 이벤트 발생을 포착할 수 있게 됩니다. 말 그대로 듣고
있는 것으로 비유하면 되겠습니다. 그리고 등록된 이벤트가 발생하면 이벤트 리스너를 등록할 때 함께 인자로 전달한 이벤트리스너 콜백함수
를 실행하게 됩니다.
이 매서드는 첫 번쨰 인자로 이벤트의 타입
을,
두 번째 인자에는
null
handleEvent()
가 구현된 객체
그리고 세 번째 인자에는 이 이벤트와 관련하여 추가적인 설정을 추가할 수 있는 옵션객체
, 또는 useCapture에 해당하는 boolean
값을 받습니다.
제가 궁금했던 것은, 그러면 2번째 인자에 자바스크립트 함수가 오는 경우, 일반함수, 익명함수, 화살표 함수에 따라서 어떤 차이가 있는지에 대한 것이었습니다.
결론은 this 바인딩에 대한 차이였고, 이는 자바스크립트 함수의 특성으로 인한 것이었습니다.
일반함수, 익명함수 - 자체적으로 this를 형성합니다
화살표함수 - 화살표함수를 담고 있는 함수(여기서는 addEventListener)의 this 바인딩을 상속받습니다
text-align 속성은 block, 또는 테이블 cell 요소에 주었을 때, inline 속성의 컨텐츠를 정렬할 수 있는 CSS 속성입니다.
저는 Generate, Copy 버튼을 가운데 정렬하고 싶었는데, display:flex
를 사용하지 않고 싶었습니다.
그래서 버튼들을 감싸고 있는 text-align 속성을 통해서 center값을 주었습니다.
//버튼 컨테이너와 버튼 CSS 코드
.btn-container {
text-align: center;
:nth-child(1) {
margin-right: 10px;
}
}
button {
padding: 0.5rem;
user-select: none;
}
text-align: center 적용 결과는 아래와 같습니다.
/* offset-x | offset-y | blur-radius | color */
text-shadow: 1px 1px 2px black;
https://www.w3schools.com/css/css_specificity.asp
명시도가 높은 스타일이 최종적으로 화면에 반영됩니다.
명시도 점수는 다음과 같이 적용됩니다.
<h1 style="color: pink;">heading</h1>
#textbox
.test, :active , [href]
h1, ::after, ::before
또한, 같은 명시도라면, 나중에 적용된 스타일이 최종적으로 반영됩니다.
html 문서의 <style>
태그 안의 스타일이, 외부 css 파일의 스타일보다 명시도가 높게 반영됩니다.
CSS 속성들에는 default 값이 있습니다. 한 번 확인해보죠.
참고: https://www.w3schools.com/cssref/css_default_values.php
line-height 를 사용할 때는 유닛없는 숫자를 사용하는 것이 가장 선호되는 방법이라고 합니다.
가령 아래처럼요.
p{
line-height: 1.1;
}