ํ์ผ input CSS ์คํ์ผ๋ง
ํค๋ณด๋ ์ ๊ทผ์ฑ - focus-visible
input์ change ์ด๋ฒคํธ ์ ํํ ํ์ผ ์ด๋ฆ ๋ณด์ฌ์ฃผ๊ธฐ
๋ฒ๊ทธ ์์
input[type="file"]์ ๋ณด์ด์ง ์๊ฒ ์จ๊ฒผ๋ค.
ํ์ผ ์ด๋ฆ์ ๋ณด์ฌ์ค input์ readOnly๋ก ๋ง๋ค์๋ค.
label์ fontawesome icon์ ๋ฃ์ด์ฃผ์๋ค.
Styling an input type="file" button ์ฐธ๊ณ
//- edit-profile.pug
form(method="POST", enctype="multipart/form-data")
div.file-upload
input(value="Avatar", readOnly)#avatar__fileName.file-upload__fileName
label(for="avatar")
i.fas.fa-file-import
input(name="avatar", type="file", accept="image/*", id="avatar")
// form.scss
.file-upload {
display: flex;
justify-content: space-between;
font-size: $font-small;
border: 1px solid $light-grey;
border-radius: 4px;
margin: 2px 0;
input[type="file"] {
position: absolute;
left: -99999rem;
overflow: hidden;
}
.file-upload__fileName {
width: 80%;
border-style: none;
background-color: transparent;
color: $grey;
}
.fas.fa-file-import {
color: white;
padding: 0 10px;
line-height: 44px;
cursor: pointer;
}
}
button๊ณผ input์ ๋ง์ฐ์ค๋ก ํด๋ฆญํ์ ๋ ๋ํ๋๋ outline์ ์์ ๊ณ ์ ํ๋ค.
๊ทธ๋ฐ๋ฐ ์ด๋ฅผ ๋ฌดํฑ๋๊ณ ์์ ๋ฉด ํด๋น ์์์ ํค๋ณด๋๋ก๋ ์ ๊ทผํ ์ ์๊ฒ ๋๋ค.
๋ฐ๋ผ์, ๋ง์ฐ์ค๋ก ํด๋ฆญํ์ ๋๋ง outline์ ์์ ๊ณ , ํค๋ณด๋๋ก ์ ๊ทผ ์์๋ focus ๋๋๋ก ์ฆ outline์ด ๋ํ๋๋๋ก ํด์ผ ํ๋ค.
button
์ ๊ฒฝ์ฐ focus-visible๋ก ํด๊ฒฐ์ด ๊ฐ๋ฅํ๋ค.
// styles.css
button {
cursor: pointer;
border-style: none;
}
// ํค๋ณด๋๋ก ์ ๊ทผ ์
button:focus-visible {
outline: $blue solid 1px;
}
// ๋ง์ฐ์ค๋ก ์ ๊ทผ ์
button:focus:not(:focus-visible) {
outline: none;
}
๊ทธ๋ฌ๋, input
์ focus-visible๋ก ํด๊ฒฐ์ด ์๋๋ค.
ํค๋ณด๋ ์
๋ ฅ์ ์ง์ํ๋ ์์๋ ๋ง์ฐ์ค๋ก ํด๋ฆญํด๋ :focus-visible์ด ์ ์ฉ๋์ด ์์ฒ๋ผ ์์ฑํ๋ฉด ํค๋ณด๋์ ๋ง์ฐ์ค๋ก ํด๋ฆญํ ๋ ๋ชจ๋ ์ฌ์ ํ outline์ด ๋ํ๋๋ค.
๋ค๋ง, video player์ ๋ณผ๋ฅจ ๋ฐ์ ํ์๋ผ์ธ์ ํค๋ณด๋ ์ ๋ ฅ์ ์ง์ํ์ง ์๋ input[type="range"]์ด๊ธฐ ๋๋ฌธ์ :not(:focus-visible)์ ์ฌ์ฉํ ์ ์๋ค.
Vertical text alignment in buttons and inputs
ํ
์คํธ๋ฅผ ๋ด๊ณ ์๋ button ํน์ input์ ์, ์๋ padding์ ์ ๊ฑฐ
ํ๊ณ , line-height๋ฅผ
button ํน์ input์ height ๊ฐ๊ณผ ๋์ผํ๊ฒ
์ค์ ํ๋ค.
client ํด๋์ fileName.js ํ์ผ์ ๋ง๋ ํ webpack.config.json ํ์ผ์ ์์ ํ๋ค.
upload.pug์ edit-profile.pug ํ์ผ์์ script๋ฅผ ์ถ๊ฐํ๋ค.
webpack์ ๋ค์ ์์ํ๋ฉด assets ํด๋์ fileName.js ํ์ผ์ด ์ถ๊ฐ๋๋ค.
MDN - ์น ์ดํ๋ฆฌ์ผ์ด์
์์ ํ์ผ ์ฌ์ฉํ๊ธฐ ๐ฅ
MDN - HTMLElement: change event
Display file name in page after selecting file in file input ์ฐธ๊ณ
event.srcElement๋ ๋ ์ด์ ์ฌ์ฉ๋์ง ์๊ธฐ ๋๋ฌธ์ ๋์ event.target์ ์ฌ์ฉํ๋ค.
event.target.files๋ ํ์ผ๋ค์ ๋ํ ์ ๋ณด๋ฅผ ๋ด๊ณ ์๋ ๋ฐฐ์ด์ด๋ค.
๋ฐฐ์ด์ ์์์ธ ๊ฐ๊ฐ์ ํ์ผ์ ๊ฐ์ฒด๋ก์ name, size, type ์์ฑ์ ๊ฐ์ง๋ค.
๋ฐ๋ผ์, event.target.files[0].name
์ ํตํด ํ์ผ ์ด๋ฆ์ ์ป์ด์จ ํ ์ด๋ฅผ ํ์ผ ์ด๋ฆ์ ๋ณด์ฌ์ค input์ value ๊ฐ์ ํ ๋นํ๋ค.
๊ทธ๋ฐ๋ฐ ์ฒ์์ cannot read property 'addeventlistener' of null
์๋ฌ๊ฐ ๋ด๋ค.
ํ๋กํ ์์ ํ์ด์ง๋ก ๊ฐ๋ฉด videoInput์ ์ฐพ์ ์ ์๋ค๊ณ ๋จ๊ณ , ๋น๋์ค ์
๋ก๋ ํ์ด์ง๋ก ๊ฐ๋ฉด avatarInput์ ์ฐพ์ ์ ์๋ค๊ณ ๋ด๋ค.
script ํ๊ทธ์ defer ์ต์
์ ์ถ๊ฐํ๊ณ ์ด๋ฅผ head ์์ผ๋ก ์ฎ๊ฒจ๋ ํด๊ฒฐ๋์ง ์์๋ค.
์์ ํด๋น ์๋ฆฌ๋จผํธ๋ฅผ ๋ฐ์์จ ๊ฒ์ด ํ์คํ ํ์ธ๋๋ฉด ํด๋น ์ด๋ฒคํธ๋ฅผ ๊ฐ์งํ ์ ์๋๋ก if ๊ตฌ๋ฌธ
์ ์ฌ์ฉํ๋ค.
// fileName.js
const avatarInput = document.getElementById("avatar");
const videoInput = document.getElementById("video");
const thumbInput = document.getElementById("thumb");
const avatarFileName = document.getElementById("avatar__fileName");
const videoFileName = document.getElementById("video__fileName");
const thumbFileName = document.getElementById("thumb__fileName");
if (avatarInput) {
const showAvatarFileName = (event) => {
avatarFileName.value = event.target.files[0].name;
};
avatarInput.addEventListener("change", showAvatarFileName);
}
if (videoInput) {
const showVideoFileName = (event) => {
videoFileName.value = event.target.files[0].name;
};
videoInput.addEventListener("change", showVideoFileName);
}
if (thumbInput) {
const showThumbFileName = (event) => {
thumbFileName.value = event.target.files[0].name;
};
thumbInput.addEventListener("change", showThumbFileName);
}
์๋ํ ๋๋ก ๋ณด์ด์ง ์๋ ๋ถ๋ถ๋ค์ ๋ฐ๊ฒฌํด์ ๋ค์ ์์ ์ ํ๋ค.
๋ณผ๋ฅจ ๋ฐ๋ฅผ ์์ง์ฌ ์์๊ฑฐ ์ํ์์(video.muted) ๋ณผ๋ฅจ ์
์ํ๋ก ๋ง๋ค๋ฉด, ์์๊ฑฐ ์์ด์ฝ์ด ๋ณผ๋ฅจ ์
์์ด์ฝ์ผ๋ก ๋ฐ๋๋๋ก ํ๋ค.
๋ณผ๋ฅจ ๋ฐ๋ฅผ ์์ง์ฌ ๋ณผ๋ฅจ ์
์ํ์์ ์์๊ฑฐ ์ํ๋ก ๋ง๋ค๋ฉด(value === "0"), ๋ณผ๋ฅจ ์
์์ด์ฝ์ด ์์๊ฑฐ ์์ด์ฝ์ผ๋ก ๋ฐ๋๋๋ก ํ๋ค.
// videoPlayer.js
const handleVolumeChange = (event) => {
const {
target: { value },
} = event;
if (video.muted) {
video.muted = false;
muteBtn.innerHTML = "<i class='fas fa-volume-up'></i>";
}
if (value === "0") {
video.muted = true;
muteBtn.innerHTML = "<i class='fas fa-volume-mute'></i>";
}
volumeValue = value;
video.volume = volumeValue;
};
๋ค์ด๋ก๋๋ฅผ ์์ํด์ ์๋ฃํ๊ธฐ ์ ๊น์ง ๋ค์ด๋ก๋ ๋ฒํผ์ ๋นํ์ฑํ(disabled) ํ๋ค.
์ด๋ก ์ธํด ๋ค์ด๋ก๋ ๋ฒํผ์ด ๋๋ฆฌ์ง๋ ์์ง๋ง :hover์ :active์ ์ค์ ํ transition ๊ฐ๋ค๋ก ์ธํด ๋ฒํผ ์์ ๋ง์ฐ์ค๋ฅผ ๊ฐ์ ธ๊ฐ์ ๋ ํจ๊ณผ๊ฐ ์๊ธด๋ค.
์ด๋ฅผ ๋ง๊ธฐ ์ํด :not([disabled])
๋ฅผ ์ฌ์ฉํ๋ค.
// upload.scss
&:hover:not([disabled]) {
background-color: $red;
color: white;
}
&:active:not([disabled]) {
opacity: 0.8;
}
ํฐ์ ์์ด์ฝ์ ํฌ๋ช ๋ฐฐ๊ฒฝ์ ์ฌ์ฉํ๋๊น ํฐ์ ์์์์ ๋น๋์ค ํ๋ ์ด์ด๊ฐ ์ ๋ณด์ฌ์ ๋ฐฐ๊ฒฝ ์์ ๋ฐ๊ฟจ๋ค.