CSS - Flexible Box

|

Flexible Box

Flexible Box는 CSS3에 처음 소개된 기능으로 반응형 웹을 아주 쉽게 만들 수 있는 기술입니다. 기존의 속성들로는 박스의 배치 순서를 변경하거나 자유롭게 바꾸는 것이 불가능했지만, Flexible Box를 이용하면 아주 쉽고 자유롭게 다양한 화면을 구성할 수 있습니다.

기존에는 float와 같은 요소들이 있었으나 화면의 요소들을 ‘배치’하는 기술이 아니었습니다.

축의 방향

Flexible Box는 주축과 교차축이 있습니다. 축의 방향은 가장 중요한 요소로 방향이 가로인경우는 왼쪽에서 오른쪽으로, 방향이 세로인 경우는 위에서 아래쪽으로 박스들이 배치됩니다.


Flexible Box 작동을 위한 기본 설정

아주 간단한 Flexible Box의 기본 설정은 다음과 같습니다.

#wrap {
  display: -webkit-flex;
  display: flex;
  width: 90%;
  height: 500px;
  margin: 0 auto;
  background: orange;
}

flexible-direction

flex-direction 속성을 이용해서 자식 상자들의 방향을 정할 수 있습니다.

  • row : 박스를 왼쪽에서 오른쪽으로 배치
  • row-reverse
  • column : 박스를 위에서 아래로 배치
  • column-reverse
#wrap {
  display: -webkit-flex;
  display: flex;
  flex-direction: row;
  ...
}

예제

<template>
  <div id="wrap">
    <div></div>
    <div></div>
    <div></div>
  </div>
</template>

<script>
export default {
  name: "App",
};
</script>

<style>
#wrap {
  display: -webkit-flex;
  display: flex;
  flex-direction: row;
  width: 90%;
  height: 500px;
  margin: 0 auto;
  background: white;
  border: 2px solid black;
}

#wrap div {
  width: 33.333%;
}

#wrap div:first-child {
  background: orange;
}

#wrap div:nth-child(2) {
  background: violet;
}

#wrap div:nth-child(3) {
  background: teal;
}
</style>

Image

아이템을 여러 줄로 배치하기

기본적으로 Flexible Box 내의 자식 박스들은 한 줄로만 배치됩니다. 만약 여러 줄로 배치하고 싶은 경우에는 flex-wrap 속성을 넣어줘야 합니다. 사용해야 합니다.

  • nowrap(기본값) : 박스를 한 줄로 배치
  • wrap : 박스를 여러 줄로 배치
  • wrap-reverse

flex-flow

flex-flow를 이용해서 flex-directionflex-wrap을 한 번에 설정할 수도 있습니다.

#wrap {
  display: -webkit-flex;
  display: flex;
  flex-flow: row wrap;
  ...
}

justify-content

주축 방향으로 박스를 정렬하는 명령어입니다.

  • flex-start(기본값)
  • flex-end
  • center
  • space-between
  • space-around

align-items

교차축 방향으로 박스를 배치할 경우에는 align-items 속성을 이용할 수 있습니다.

  • stretch(기본값) : 박스를 확장해서 배치
  • flex-start
  • flex-end
  • center
  • baseline : 시작점에 배치되는 자식 박스의 글자 베이스 라인에 맞춰 배치

예제

<template>
  <div id="wrap">
    <div></div>
    <div></div>
    <div></div>
  </div>
</template>

<script>
export default {
  name: "App",
};
</script>

<style>
#wrap {
  display: -webkit-flex;
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  width: 90%;
  height: 500px;
  margin: 0 auto;
  background: white;
  border: 2px solid black;
}

#wrap div {
  width: 33.33%;
  height: 200px;
}

#wrap div:first-child {
  background: orange;
}

#wrap div:nth-child(2) {
  background: violet;
}

#wrap div:nth-child(3) {
  background: teal;
}
</style>

Image

Vue.js 3.0 기본 레이아웃 - (4) Navigation Drawer 슬라이딩 에니메이션

|

Navigation Drawer Slide 애니메이션

기존 코드에서 아래 부분에 애니메이션이 추가되었습니다.

<script setup>
let isDrawerOpened = false;

const toggleDrawer = () => {
  isDrawerOpened = !isDrawerOpened;
  if (isDrawerOpened) {
    document.getElementById("drawer").style.width = "200px";
  } else {
    document.getElementById("drawer").style.width = "0px";
  }
};
</script>

#drawer {
  display: flex;
  flex-direction: column;
  width: 0px;
  height: 100vh;
  background: darkcyan;
  color: white;
  transition: 0.2s;
  overflow-x: hidden;
}

전체 코드

<template>
  <div id="wrapper">
    <!-- Navigation Drawer -->
    <div id="drawer">
      <div id="drawer-header">SnowDeer Drawer</div>
      <div id="drawer-content">
        <div id="drawer-menu-item">
          <i class="bi bi-house"></i>
          <span>Home</span>
        </div>
        <div id="drawer-menu-item">
          <i class="bi bi-gift"></i>
          <span>Hello</span>
        </div>
        <div id="drawer-menu-item">
          <i class="bi bi-info-square"></i>
          <span>About</span>
        </div>
      </div>
    </div>
    <!-- Main -->
    <div id="main">
      <!-- AppBar -->
      <div id="appbar">
        <div id="hamburg-menu" class="h-center v-center" @click="toggleDrawer">
          <i class="bi bi-list"></i>
        </div>
        <div id="title" class="v-center">AppBar Title</div>
        <div id="action-items">
          <i class="action-item bi bi-heart"></i>
          <i class="action-item bi bi-three-dots-vertical"></i>
        </div>
      </div>
      <!-- Content -->
      <div id="content"></div>
    </div>
  </div>
</template>

<script setup>
let isDrawerOpened = false;

const toggleDrawer = () => {
  isDrawerOpened = !isDrawerOpened;
  if (isDrawerOpened) {
    document.getElementById("drawer").style.width = "200px";
  } else {
    document.getElementById("drawer").style.width = "0px";
  }
};
</script>

<style>
.h-center {
  display: flex;
  flex-direction: row;
  justify-content: center;
}

.v-center {
  display: flex;
  flex-direction: row;
  align-items: center;
}

#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#wrapper {
  display: -webkit-flex;
  display: flex;
  flex-flow: row wrap;
  justify-content: flex-start;
  width: 100vw;
  height: 100vh;
  margin: 0 auto;
}

#main {
  flex: 1;
  flex-flow: column wrap;
  justify-content: flex-start;
  background: #bbe4e9;
  transition: margin-left 0.5s;
}

#appbar {
  display: flex;
  flex-direction: row;
  height: 48px;
  background: #edb1f1;
}

#hamburg-menu {
  width: 48px;
  height: 48px;
  background: #d59bf6;
  cursor: pointer;
}

#title {
  flex: 1;
  height: 48px;
}

#action-items {
  display: flex;
  flex-direction: row;
  height: 48px;
  background: #d59bf6;
}

.action-item {
  width: 48px;
  height: 48px;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
}

#drawer {
  display: flex;
  flex-direction: column;
  width: 0px;
  height: 100vh;
  background: darkcyan;
  color: white;
  transition: 0.2s;
  overflow-x: hidden;
}

#drawer-header {
  width: 100%;
  height: 100px;
  padding: 20px;
  background: teal;
}

#drawer-content {
  flex: 1;
}

#drawer-menu-item {
  padding: 16px;
  cursor: pointer;
}

#drawer-menu-item:hover {
  color: black;
  background: turquoise;
}
</style>

Vue.js 3.0 기본 레이아웃 - (3) Navigation Drawer 레이아웃

|

Navigation Drawer

<template>
  <div id="wrapper">
    <div id="drawer">
      <div id="drawer-header">SnowDeer Drawer</div>
      <div id="drawer-content">
        <div id="drawer-menu-item">
          <i class="bi bi-house"></i>
          <span>Home</span>
        </div>
        <div id="drawer-menu-item">
          <i class="bi bi-gift"></i>
          <span>Hello</span>
        </div>
        <div id="drawer-menu-item">
          <i class="bi bi-info-square"></i>
          <span>About</span>
        </div>
      </div>
    </div>
    <div id="main">
      <div id="appbar">
        <div id="hamburg-menu" class="h-center v-center">
          <i class="bi bi-list"></i>
        </div>
        <div id="title" class="v-center">AppBar Title</div>
        <div id="action-items">
          <i class="action-item bi bi-heart"></i>
          <i class="action-item bi bi-three-dots-vertical"></i>
        </div>
      </div>
      <div id="content"></div>
    </div>
  </div>
</template>

<style>
.h-center {
  display: flex;
  flex-direction: row;
  justify-content: center;
}

.v-center {
  display: flex;
  flex-direction: row;
  align-items: center;
}

#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#wrapper {
  display: -webkit-flex;
  display: flex;
  flex-flow: row wrap;
  justify-content: flex-start;
  width: 100vw;
  height: 100vh;
  margin: 0 auto;
}

#appbar {
  display: flex;
  flex-direction: row;
  height: 48px;
  background: #edb1f1;
}

#hamburg-menu {
  width: 48px;
  height: 48px;
  background: #d59bf6;
  cursor: pointer;
}

#title {
  flex: 1;
  height: 48px;
}

#action-items {
  display: flex;
  flex-direction: row;
  height: 48px;
  background: #d59bf6;
}

.action-item {
  width: 48px;
  height: 48px;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
}

#drawer {
  display: flex;
  flex-direction: column;
  width: 200px;
  height: 100vh;
  background: darkcyan;
  color: white;
}

#drawer-header {
  width: 200px;
  height: 100px;
  padding: 20px;
  background: teal;
}

#drawer-content {
  flex: 1;
}

#drawer-menu-item {
  padding: 16px;
  cursor: pointer;
}

#drawer-menu-item:hover {
  color: black;
  background: turquoise;
}

#main {
  flex: 1;
  flex-flow: column wrap;
  justify-content: flex-start;
  background: #bbe4e9;
}
</style>

image

CSS - 폰트 크기 (em vs rem)

|

화면 크기에 가변적인 폰트 사이즈

화면 크기에 따라 폰트의 크기를 변경하고 싶을 때가 있습니다. 폰트 크기를 px로 설정하면 화면 크기와 무관하게 크기가 고정됩니다. (단, 최신 브라우저들은 px 단위에서도 화면 크기에 따라 폰트 크기가 조절됩니다.)

화면 크게에 따라 반응성으로 폰트 크기를 조절하기 위해 em 단위를 사용합니다. em 단위는 대문자 M1em으로 표현한 것으로 16px1em 입니다.

em의 단점, rem의 등장

em은 화면 크기에 따라 폰트의 크기가 반응성을 가지며 변하지만, 부모 컨테이너의 글자 크기를 상속받는다는 단점이 있습니다. 복잡한 레이아웃에서는 사용하기 불편할 수 있습니다.

그래서 나온 것이 rem 입니다. 웹 문서의 최상위인 <html>, </html>를 기준으로 하기 때문에 상속 문제가 발생하지 않아 유용하게 사용할 수 있습니다.

vw, vh, vmin, vmax 단위

rem은 화면 크기에 따라 폰트의 크기가 변하기는 하지만 특정 단위를 기준으로 폰트 크기가 변할 뿐, 화면 비율에 따라 역동적으로 변하지는 않습니다. CSS3에서 추가된 vw, vh, vmin, vmax 등을 이용하면 화면 비율에 따라 역동적으로 변하는 폰트 크기를 얻을 수 있습니다.

p {
  font-size: 5vw;
}

위와 같이 폰트 크기를 5vw로 한 경우 웹브라우저 너비의 5%를 의미합니다. 여기서 vviewport를 의미합니다.

vmin은 너비와 높이 중 짧은 쪽을 기준으로 합니다.

Ubuntu 모니터 끄는 명령어

|