input에 입력값을 입력하기 전까지 placeholder는 사라지지 않는다.

이는 input 창이 포커싱되어있는지 헷갈리게 할 수 있어 UX를 떨어뜨릴 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
input:focus::-webkit-input-placeholder,
textarea:focus::-webkit-input-placeholder {
/* WebKit browsers */
color: transparent;
}

input:focus:-moz-placeholder,
textarea:focus:-moz-placeholder {
/* Mozilla Firefox 4 to 18 */
color: transparent;
}

input:focus::-moz-placeholder,
textarea:focus::-moz-placeholder {
/* Mozilla Firefox 19+ */
color: transparent;
}

input:focus:-ms-input-placeholder,
textarea:focus:-ms-input-placeholder {
/* Internet Explorer 10+ */
color: transparent;
}
  • 크로스 브라우징을 고려하여 CSS를 추가해주었다.
  • 포커스가 되었을 때, placeholder 색상을 투명하게 설정하도록 해준다.

댓글 공유

내부 경계(border) 효과 주기

문제

문제사진

CSS로 작업을 하다가 경계가 검정색 바탕 부분과 border에 약간의 단차가 생기는 문제가 있었다.

마크업 구조는 다음과 같다.

1
2
3
4
5
6
<div>
<h2>나의 자산 목표 금액 계산기</h2>
<div>
<h3>목표 금액 계산기란?</h3>
</div>
</div>
  • h2 태그에 배경색이 검정색이다.
  • h2 태그와 형제태그인 div 태그에 보더를 주었더니 단차가 생겼다.

해결방법

1
box-shadow: 0 0 0 1px gray inset;
  • box-shadow 효과를 inset으로 주어서 보더 처럼 보이도록 구현했다.

댓글 공유

:not 셀렉터

1
2
3
4
5
<ul class="grid">
<li class="grid__child"></li>
<li class="grid__child"></li>
<li class="grid__child"></li>
</ul>
1
2
3
4
5
6
7
8
9
10
11
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, 15rem);
grid-gap: 1rem;
}

.grid__child {
background: rgba(0, 0, 0, 0.1);
border-radius: 0.5rem;
aspect-ratio: 1/1;
}
  • 이렇게 생긴 그리드 아이템에 마우스 올린 요소만 hover 효과를 주고 나머지 요소는 공통적으로 다른 효과를 주고 싶을 때, :not, :hover 셀렉터가 유용하다.
1
2
3
.grid:hover .grid__child:not(:hover) {
opacity: 0.3;
}

  • 이렇게 마우스가 올라간 요소만 제외하고 opacity가 변경되는 것을 볼 수 있다.

하지만 한가지 문제점은 grid의 gap이 있을 경우 item에 마우스가 올라갔을 때 뿐만 아니라 gap에 마우스가 올라갔을 때에도 해당 css가 적용된다.

이를 해결하기 위해서 부모 요소에는 pointer-events: none을 주고 자식 요소에는 pointer-events: auto를 줘서 해결할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, 15rem);
grid-gap: 2rem;
pointer-events: none;
}
.grid__child {
background: rgba(0, 0, 0, 0.1);
border-radius: 0.5rem;
aspect-ratio: 1/0.5;
pointer-events: auto;
transition: opacity 0.3s;
}

.grid:hover .grid__child:not(:hover) {
opacity: 0.3;
}

TroubleShooting

pointer-events: none 속성은 hover이벤트 뿐만 아니라 다른 모든 이벤트도 무시한다. 그래서 scroll이 되어야하는 경우에 스크롤이 되지 않는 문제가 발생할 수 있다.

이를 해결하기 위해서는 해당 부모요소를 감싸는 container 박스를 생성하는 것이다.

1
2
3
4
5
6
7
8
9
10
11
<div class="container">
<ul class="grid">
<li class="grid__child"></li>
<li class="grid__child"></li>
<li class="grid__child"></li>
<li class="grid__child"></li>
<li class="grid__child"></li>
<li class="grid__child"></li>
<li class="grid__child"></li>
</ul>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.container {
width: 400px;
height: 300px;
overflow: auto;
}

.grid {
display: grid;
grid-template-columns: repeat(auto-fit, 15rem);
grid-gap: 2rem;
pointer-events: none;
}
.grid__child {
background: rgba(0, 0, 0, 0.1);
border-radius: 0.5rem;
aspect-ratio: 1/0.5; // 가로 세로 비율
pointer-events: auto;
transition: opacity 0.3s;
}

.grid:hover .grid__child:not(:hover) {
opacity: 0.3;
}

li {
list-style-type: none;
}
  • grid 요소를 감싸는 container 요소에 scroll을 가능하게 overflow:auto 속성을 주면 스크롤도 작동하고 gap 부분에서 hover 이벤트도 방지할 수 있다.

댓글 공유

Accordion

default

active

1. HTML 마크업 설계

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<button class="accordion">Section 1</button>
<div class="panel">
<p>Lorem ipsum...</p>
</div>

<button class="accordion">Section 2</button>
<div class="panel">
<p>Lorem ipsum...</p>
</div>

<button class="accordion">Section 3</button>
<div class="panel">
<p>Lorem ipsum...</p>
</div>

2. CSS 스타일링

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
text-align: left;
border: none;
outline: none;
}

/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
.accordion:hover {
background-color: #ccc;
}

/* Style the accordion panel. Note: hidden by default */
.panel {
padding: 0 18px;
background-color: white;
max-height: 0;
overflow: hidden;
transition: max-height 0.4s ease-out;
}

.active {
max-height: 100vh;
}

3. React 로직

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Accordion.jsx
import { useState } from "react";
import "./styles/main.css";

function Accordion({ title, info }) {
const [showInfo, setShowInfo] = useState(false);
return (
<>
<button className="accordion" onClick={() => setShowInfo(!showInfo)}>
{title}
</button>
<div className={`panel ${showInfo ? "active" : ""}`}>
<p>{info}</p>
</div>
</>
);
}

export default Accordion;

댓글 공유

기본적인 HTML구조와 CSS로 다음과 같은 form을 만들 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<!DOCTYPE html>
<html>
<style>
input[type="text"],
select {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}

input[type="submit"] {
width: 100%;
background-color: #4caf50;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
border-radius: 4px;
cursor: pointer;
}

input[type="submit"]:hover {
background-color: #45a049;
}

div {
border-radius: 5px;
background-color: #f2f2f2;
padding: 20px;
}
</style>
<body>
<h3>Using CSS to style an HTML Form</h3>

<div>
<form action="/action_page.php">
<label for="fname">First Name</label>
<input
type="text"
id="fname"
name="firstname"
placeholder="Your name.."
/>

<label for="lname">Last Name</label>
<input
type="text"
id="lname"
name="lastname"
placeholder="Your last name.."
/>

<label for="country">Country</label>
<select id="country" name="country">
<option value="australia">Australia</option>
<option value="canada">Canada</option>
<option value="usa">USA</option>
</select>

<input type="submit" value="Submit" />
</form>
</div>
</body>
</html>

commonForm

focused Inputs

1
2
3
input[type="text"]:focus {
background-color: lightblue;
}

icon/image 삽입하기

1
2
3
4
5
6
7
8
9
10
11
12
input[type="text"] {
width: 100%;
box-sizing: border-box;
border: 2px solid #ccc;
border-radius: 4px;
font-size: 16px;
background-color: white;
background-image: url("searchicon.png");
background-position: 10px 10px;
background-repeat: no-repeat;
padding: 12px 20px 12px 40px;
}

icon

animated Search Input

1
2
3
4
5
6
7
input[type="text"] {
transition: width 0.4s ease-in-out;
}

input[type="text"]:focus {
width: 100%;
}

textarea 사이즈 재조정 방지하기

1
2
3
4
5
6
7
8
9
10
11
textarea {
width: 100%;
height: 150px;
padding: 12px 20px;
box-sizing: border-box;
border: 2px solid #ccc;
border-radius: 4px;
background-color: #f8f8f8;
font-size: 16px;
resize: none;
}
  • resize 속성을 none으로 주어 사이즈 재조정을 막는다.

반응형 form 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
* {
box-sizing: border-box;
}

input[type="text"],
select,
textarea {
width: 100%;
padding: 12px;
border: 1px solid #ccc;
border-radius: 4px;
resize: vertical;
}

label {
padding: 12px 12px 12px 0;
display: inline-block;
}

input[type="submit"] {
background-color: #04aa6d;
color: white;
padding: 12px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
float: right;
}

input[type="submit"]:hover {
background-color: #45a049;
}

.container {
border-radius: 5px;
background-color: #f2f2f2;
padding: 20px;
}

.col-25 {
float: left;
width: 25%;
margin-top: 6px;
}

.col-75 {
float: left;
width: 75%;
margin-top: 6px;
}

/* Clear floats after the columns */
.row::after {
content: "";
display: table;
clear: both;
}

/* Responsive layout - when the screen is less than 600px wide, make the two columns stack on top of each other instead of next to each other */
@media screen and (max-width: 600px) {
.col-25,
.col-75,
input[type="submit"] {
width: 100%;
margin-top: 0;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<h2>Responsive Form</h2>
<p>
Resize the browser window to see the effect. When the screen is less than
600px wide, make the two columns stack on top of each other instead of next to
each other.
</p>

<div class="container">
<form action="/action_page.php">
<div class="row">
<div class="col-25">
<label for="fname">First Name</label>
</div>
<div class="col-75">
<input
type="text"
id="fname"
name="firstname"
placeholder="Your name.."
/>
</div>
</div>
<div class="row">
<div class="col-25">
<label for="lname">Last Name</label>
</div>
<div class="col-75">
<input
type="text"
id="lname"
name="lastname"
placeholder="Your last name.."
/>
</div>
</div>
<div class="row">
<div class="col-25">
<label for="country">Country</label>
</div>
<div class="col-75">
<select id="country" name="country">
<option value="australia">Australia</option>
<option value="canada">Canada</option>
<option value="usa">USA</option>
</select>
</div>
</div>
<div class="row">
<div class="col-25">
<label for="subject">Subject</label>
</div>
<div class="col-75">
<textarea
id="subject"
name="subject"
placeholder="Write something.."
style="height:200px"
></textarea>
</div>
</div>
<br />
<div class="row">
<input type="submit" value="Submit" />
</div>
</form>
</div>

댓글 공유

[attribute]

특정 attribute를 선택하기 위해 사용하는 선택자이다.

1
2
3
a[target] {
background-color: yellow;
}
  • a 태그의 target attribute가 선언된 요소를 선택한다.
1
2
3
a[target="_blank"] {
background-color: yellow;
}
  • attribute 값에 해당하는 요소를 선택한다.

정확히 특정 단어 포함하는 attribute 선택

1
2
3
[title~="flower"] {
border: 5px solid yellow;
}
1
2
3
4
5
6
7
8
9
<h2>CSS [attribute~="value"] Selector</h2>
<p>
All images with the title attribute containing the word "flower" get a yellow
border.
</p>

<img src="klematis.jpg" title="klematis flower" width="150" height="113" />
<img src="img_flwr.gif" title="flower f" width="224" height="162" />
<img src="img_tree.gif" title="tree" width="200" height="358" />

  • title 속성에 “flower” 단어가 포함된 요소를 선택한다.

띄어쓰기로 구분된 요소는 개별요소로 취급하짐나, 하이푼(-)으로 구분된 요소는 여기서 제외된다.

특정 단어를 포함하는 attribute 선택

1
2
3
[class|="top"] {
background: yellow;
}
1
2
3
4
5
<h2>CSS [attribute|="value"] Selector</h2>

<h1 class="top-header">Welcome</h1>
<p class="top-text">Hello world!</p>
<p class="topcontent">Are you learning CSS?</p>

include value

  • top이라는 단어가 포함된 요소만 선택하는 것을 확인할 수 있다. (-으로 구분할 수 있다.)

특정 단어로 시작하는 attribute 속성 선택

1
2
3
[class^="top"] {
background: yellow;
}
1
2
3
4
5
<h2>CSS [attribute|="value"] Selector</h2>

<h1 class="top-header">Welcome</h1>
<p class="top-text">Hello world!</p>
<p class="topcontent">Are you learning CSS?</p>

startwith

특정 단어로 끝나는 attribute 속성 선택

1
2
3
[class$="test"] {
background: yellow;
}

특정 값을 포함하는 attribute 속성을 선택

1
2
3
[class*="te"] {
background: yellow;
}

댓글 공유

image sprites

이미지 스프라이트는 단일 이미지에 포함된 이미지 모음이다.

이미지가 많은 웹 페이지 로드하는데 많은 시간이 걸릴 수 있고 서버 요청도 여러번 발생할 수 있다.

이미지 스프라이트를 사용하면 서버 요청 수가 줄어들고 대역폭이 줄어든다.

예시

3개의 이미지를 사용하는 대신, 하나의 이미지를 사용한다.

그리고 나서 CSS로 보여주고 싶은 부분만 보여준다.

imageSprites

1
2
<img id="home" src="img_trans.gif" width="1" height="1" />
<img id="next" src="img_trans.gif" width="1" height="1" />
  • src 속성은 비워둘 수 없기 때문에 투명한 이미지를 넣어두었다.
  • 보여주고 싶은 이미지의 부분을 width, height로 정의했다.
  • background 속성으로 배경이미지를 불러오고 left, top 속성으로 배치한다.
1
2
3
4
5
6
7
8
9
10
11
#home {
width: 46px;
height: 44px;
background: url(img_navsprites.gif) 0 0;
}

#next {
width: 43px;
height: 44px;
background: url(img_navsprites.gif) -91px 0;
}

homeNext

댓글 공유

Dropdown

CSS만을 이용하여 dropdown을 구현해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<style>
.dropdown {
position: relative;
display: inline-block;
}

.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
padding: 12px 16px;
z-index: 1;
}

.dropdown:hover .dropdown-content {
display: block;
}
</style>

<div class="dropdown">
<span>Mouse over me</span>
<div class="dropdown-content">
<p>Hello World!</p>
</div>
</div>
  1. 우선 dropdown content를 열기 위한 span, button 요소를 사용한다.

  2. dropdown content는 div같은 컨테이너 요소를 사용한다.

  3. dropdown content를 CSS에 정확하게 배치하기 위해 1,2번을 div로 감싼다.

  4. wrapper div에는 position:relative 속성을 주어 기준이 되도록 하며 dropdown content에는 position:absolute 속성을 주어 dropdown button 바로 아래에 위치하도록 한다.

  5. dropdown content는 hidden 속성이 기본값이다. 그리고 hover시 아래에 보이도록 한다. 그리고 min-width 속성을 줘서 width를 갖게 한다.

이때, dropdown button 만큼 넓게 width를 갖게 하고 싶다면 width:100%로 설정해라. 작은 화면에서 스크롤을 활성화 시키려면 overflow:auto를 설정하라.

  1. border를 설정하는 것 대신 box-shadow 속성으로 카드처럼 보이게 할 수 있다.

  2. hover 속성은 dropdown menu를 보여줄 때 사용된다.

댓글 공유

Navigation Bar

Navigation Bar는 link의 목록들이다.

1
2
3
4
5
6
<ul>
<li><a href="default.asp">Home</a></li>
<li><a href="news.asp">News</a></li>
<li><a href="contact.asp">Contact</a></li>
<li><a href="about.asp">About</a></li>
</ul>

기본적인 list 스타일을 제거하기 위한 CSS는 다음과 같다.

1
2
3
4
5
ul {
list-style-type: none;
margin: 0;
padding: 0;
}

수직 Navigation Bar

1. li 요소 내부의 a태그에 display:block 선언하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ul {
list-style-type: none;
margin: 0;
padding: 0;
width: 200px;
background-color: #f1f1f1;
}

li a {
display: block;
color: #000;
padding: 8px 16px;
text-decoration: none;
}

/* Change the link color on hover */
li a:hover {
background-color: #555;
color: white;
}

추가로 active 클래스를 추가하여 현재 선택된 link를 표시해줄 수 있다. JavaScript 사용해야한다.

1
2
3
4
5
6
7
8
9
10
li a.active {
background-color: #04aa6d;
color: white;
}

/* .active 클래스는 포함하지 않는 a태그 hover시 효과 */
li a:hover:not(.active) {
background-color: #555;
color: white;
}

2. 고정된 세로 Navigation Bar

sticky side 네비게이션 바를 만드는 방법이다.

1
2
3
4
5
6
7
8
9
10
ul {
list-style-type: none;
margin: 0;
padding: 0;
width: 25%;
background-color: #f1f1f1;
height: 100%; /* Full height */
position: fixed; /* Make it stick, even on scroll */
overflow: auto; /* Enable scrolling if the sidenav has too much content */
}

수평 Navigation Bar

1. li 요소를 display:inline 속성을 준다.

1
2
3
li {
display: inline;
}

2. floating li

float

1
2
3
4
5
6
7
8
9
li {
float: left;
}

a {
display: block;
padding: 8px;
background-color: #dddddd;
}

3. 상단 고정된 Navigation Bar

fixedTop

1
2
3
4
5
ul {
position: fixed;
top: 0;
width: 100%;
}

4. sticky Navigation Bar

sticky

1
2
3
4
5
ul {
position: -webkit-sticky; /* Safari */
position: sticky;
top: 0;
}

IE는 sticky를 지원하지 않는다. Safari는 -webkit- prefix가 필요하다. 또한 top, right, left, bottom 중 적어도 하나는 지정해줘야한다.

CSS만으로 Dropdown Navigation Bar 구현하기

dropdown

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<ul>
<li><a href="#home">Home</a></li>
<li><a href="#news">News</a></li>
<li class="dropdown">
<a href="javascript:void(0)" class="dropbtn">Dropdown</a>
<div class="dropdown-content">
<a href="#">Link 1</a>
<a href="#">Link 2</a>
<a href="#">Link 3</a>
</div>
</li>
</ul>

<h3>Dropdown Menu inside a Navigation Bar</h3>
<p>Hover over the "Dropdown" link to see the dropdown menu.</p>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
ul {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #38444d;
}

li {
float: left;
}

li a,
.dropbtn {
display: inline-block;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}

li a:hover,
.dropdown:hover .dropbtn {
background-color: red;
}

li.dropdown {
display: inline-block;
}

.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
}

.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
text-align: left;
}

.dropdown-content a:hover {
background-color: #f1f1f1;
}

.dropdown:hover .dropdown-content {
display: block;
}
  • dropdown-content는 기본 display 속성이 none이다.
  • dropdown 클래스가 있는 li에 hover 했을 때, dropdown-content에 display 속성은 block으로 바꿔주었다.

댓글 공유

opacity

요소의 투명도를 설정하는 속성이다.

0 ~ 1.0 사이의 값을 가질 수 있으며 기본값은 1이다.

1
2
3
img {
opacity: 0.5;
}

exam

특징

내부의 자식 요소들에게도 상속이 된다. 그러므로 내부의 텍스트가 있다면 가독성이 떨어질 수 있으므로 조심해야한다.

또한, RGBA를 사용하여 투명도를 설정할 수 있다.

exam2

1
2
3
div {
background: rgba(76, 175, 80, 0.3); /* Green background with 30% opacity */
}

댓글 공유

loco9939

author.bio


author.job