본문 바로가기

개발 이야기/front-end

css rendering2 | box-sizing? position:absolute?

box-sizing을 content box로 했을 때와 border box로 했을 때 레이아웃이 다른 이유가 뭘까요? 하나의 div로 stitch border를 표현하려면 어떻게 할까요?

position: absolute 속성을 쓰면 왜 엘리먼트가 엉뚱한 곳에 위치하는 일이 생길까요?

 

modern box와 position을 통해 알아봅시다.

 

코드스피츠 css 렌더링 2

 

코드스피츠 css 렌더링 2

모던 박스

www.notion.so

 

another-light.tistory.com/65

 

css rendering - 기본 레이아웃 | CSS 속성은 사실 OO이다?

CSS란? CSS(Cascading Style Sheets)는 종속형 스타일 시트 언어입니다. *마크업 언어의 스타일을 웹사이트에 표현하는 데 사용합니다. HTML 요소에 선택적으로 스타일을 지정할 수 있습니다. *마크업언어:

another-light.tistory.com


Box

css rendering 과정에는 두 단계가 있습니다. geometry calculate와 fragment fill입니다. geometry calculate에서는 박스의 정확한 위치를 계산하여 배치하고, fragment fill은 박스에 색칠하는 단계입니다.

 

 

computed box

 

css 박스에서 border-box는 fragment-fill 단계에서 작동합니다. 즉, 배치 과정이 끝난 뒤 그리는 단계에서 작동하니 geometry 값에는 영향을 주지 않습니다.

 

source: 코드스피츠 강의 76 - css rendering 2회차

 

border-box 밖에는 box-shadow가 outline(border와 다름)과 같은 영역에 위치하고 있습니다. 이 역시 그림으로 표현되는 속성이니 geometry에는 영향을 주지 않습니다.

 

box-shadow는 inset 속성을 주면 border-box안에 shadow를 겹겹이 쌓을 수 있습니다. blur를 안주면 border 처럼 사용할 수도 있습니다. css box는 이렇게 geometry에 영향을 끼치지 않는 outline, box-shadow, box-shadow inset가 포함되어 보다 복잡한 박스 모델이 됩니다.

 


 

box-sizing

padding, margin, box-shadow, border는 content box 밖에 추가됩니다. geometry가 계산이 끝난 후 추가되기 때문에, 우리가 실제로 원하는 width와 height보다 더 두꺼운 박스가 그려질 수 있습니다. 만약 box-shadow와 border 등을 포함하여 박스 사이즈를 유지하고 싶으면 box-sizing: border-box 속성을 추가해야합니다.

 

오른쪽이 box-sizing: border-box 속성을 추가한 박스입니다.

.content-box {
  width: 100px;
  color: #000;
  height: 100px;
  background: pink;
  display: inline-block;
  border: 10px solid red;
}

.border-box {
  width: 100px;
  color: #fff;
  height: 100px;
  background: blue;
  display: inline-block;
  border: 10px solid green;
  box-sizing: border-box;
}

 

border를 dashed로 바꾸면 border box까지 색깔이 칠해진 걸 볼 수 있습니다. 그리고 여기에 box-shadow까지 추가하면 왼쪽처럼 border-box 밖에 칠해져 있습니다. 파란색 박스와 겹쳐져 있지만 box-shadow에 의해 파란색 박스가 밀려나진 않습니다. box-shadow가 geometry 값에 영향을 주지 않으니까요.

 

 

 

tricks

파란색 박스에 노란색 box-shadow를 추가했습니다. 여기서 빨간 박스에 position: relative 를 주면 파란색 박스 섀도우의 위로 올라옵니다. relative는 normal flow 이후에 그려지므로 box-shadow를 가립니다.

 

 

 

또한, box-shadow는 여러 개의 박스 섀도우를 그릴 수 있습니다. 처음 쓴 박스 섀도우가 맨 위에 보여지므로 두번째 박스 섀도우는 첫번째에 쓴 박스 섀도우보다 더 두꺼워야 보여지게 됩니다. 또는 border-box 안쪽에 그려지는 inset 속성을 이용할 수도 있습니다.

 

.target {
  width: 50px;
  height: 50px;
  background-color: red;
  color: #fff;
  box-shadow: 0 0 0 10px green, 0 0 0 20px red, inset 0 0 0 10px red, inset 0 0 0 20px green;
}

 

 

box-shadow는 border의 모양을 따라가는 속성을 이용해 border-radius로 아래처럼 과녁 모양을 만들 수도 있습니다. 오른쪽 과녁의 보라색은 border를 준 것입니다. 그 내외로 box-shadow가 그려집니다.

오른쪽: border-radius: 50%

 

 

stitched

stitched는 바느질한 듯 가장자리에 여백을 주고 dashed border를 사용한 디자인입니다. 테두리에 있어야할 border가 마치 안쪽에 형성된 듯 보입니다. border와 box-shadow를 사용하여 만들 수 있습니다.

 

outline은 border를 따라가지 않고 box-shadow는 border를 따라가는 특징을 활용해, 오른쪽처럼 dashed border는 둥글게 박스 모서리는 각지게 만들 수도 있습니다.

 

*codepen

stitched border

.stitched {
   width:200px;
   height: 100px;
   padding: 20px;
   margin: 10px;
   background: #ff0030;
   color: #fff;
   border: 2px dashed #fff;
   border-radius: 10px;
   outline: 10px solid #ff0030;
   box-shadow: 0 0 0 10px #ff0030;
}

 

 

 


 

 

Position

absolute, fixed 속성에 대해 알아봅시다.

 

offset

right, left 등 추상적으로 명령해도 계산이 끝나면 fixed number로 바뀝니다. geometry 계산이 끝난 후의 fixed number 값을 offset이라고 합니다. 이 값은 read only라 변경이 불가합니다.

geometry 계산을 할 때 '프레임'이라는 개념이 있습니다. 변경해야 하는 것들을 변경만 시켜놓고, 한꺼번에 재계산하는 것입니다. 우리가 offset을 요청하면 계산 queue를 지우고 다시 재계산 해야합니다. 그래서 웬만하면 offset을 쓰지 않는 게 좋습니다.

 

offset 계산

offset을 요청하면 어떻게 계산할까요? 일단 기준점인 offset parent를 찾습니다. offset 부모를 찾아 삼만리하는 데에는 몇 가지 규칙이 있습니다.

 

- offset parent가 null일 수 있다.

- recursive search, 재귀적으로 찾아나간다.

 

 

1. null인 경우

html, body 등 root element인 경우 offset parent가 없습니다. position: fixed이거나 DOM tree 바깥에 있는 경우에도 offset parent가 없습니다.

 

2. recursive search

offset parent를 찾을 때까지 부모들을 계속해서 찾아나갑니다. 이 재귀 검색을 멈추기 위해서는 몇가지 규칙이 있습니다.

- parent가 fixed면 offset parent가 null. 더 이상 찾지 않는다.

- parent position이 static이 아니면, offset parent를 찾은 것이다.

- body면 offset parent를 찾은 것이다.

- td, th, table이면 offset parent를 찾은 것이다 (하지만 실제로는 안에 div를 만들어줘야 absolute가 적용된다. 스펙에는 그렇게 써있지만 실제 동작은 이러하다)

 

⇒ 즉, DOM 상의 부모가 아니라 position absolute 또는 relative 속성을 가진 부모를 찾습니다.

⇒ offset parent ≠ DOM parent

 

scroll

우리는 offset 값 중 offsetTop, offsetScrollTop같은 것들을 사용할 수 있습니다. offset scroll은 스크롤이 생겼을 때 스크롤 영역 안의 콘텐츠 offset에 해당합니다. 진짜 콘텐츠 영역은 offsetScroll에 있고, 콘텐츠는 offset에 갇히게 됩니다.

 

사진에서 보이는 것처럼 offset은 콘텐츠 박스의 offset입니다. 박스가 (100px, 100px)이고 안의 콘텐츠가 (100px, 900px)이면 아래 같은 상황에서 offset height는 100px, offset scroll height는 900px이 됩니다.

 

source: 코드스피츠 강의 76 - css rendering 2회차

 

 

absolute

static의 위치를 기본값으로서 가집니다. 여기에 left, right를 주면 offset parent를 찾아서 left, right 값만큼 띄어주게 됩니다.

 

static 박스에 left, top을 주면 어떻게 될까요?

 

저번 포스팅에서 relative에서 top을 사용했을 때는 어떻게 되었나요? normal flow로 먼저 static한 위치를 구한 뒤 상대적인 거리만큼 이동시켜주었습니다. 하지만 static 박스 같은 경우는 normal flow 단계에서 끝납니다. 그러니 static 박스에 left, top을 주어도 실제로는 top: 100px만큼 떨어지지 않습니다.

 

<style>
.absolute {
  position: absolute;
  top: 100px;
}

.static-top {
  top: 100px;
}
</style>

<div>
  <div class="absolute"/>
  <div class="static-top"/>
</div>

 

 

 

 

 

상대적인 위치를 가리키는 left, top, right, bottom 등은 absolute일 때와 relative일 때의 의미가 조금 다릅니다.

 

- absolute: offset parent로부터의 거리

- relative: normal flow로 그렸을 때 static과의 거리

 

 

absolute 박스는 offset parent인 보라색 박스로부터 top: 100px에 위치합니다. 반면, relative 박스는 normal flow이후에 보라색 박스를 인식하고 그 베이스라인으로부터 top: 100px에 위치합니다. 그래서 relative parent의 높이만큼 absolute 박스보다 더 밑에 위치하게 됩니다.

 

https://codepen.io/roseline124/pen/zYoPdYR

 

 

 

.absolute {
  width: 200px;
  height:50px;
  background: red;
  color: white;
  position: absolute;
  top: 100px;
  left: 100px;
}

.relative-parent {
  height: 50px;
  color: white;
  position: relative;
  background: purple;
}

.relative-top {
    width: 200px;
  height:50px;
  background: green;
  position: relative;
  top: 100px;
  left: 100px;
}
<div class="relative-parent">
  relative parent
  <div class="absolute">absolute: top 100</div>  
</div>
<div class="relative-top">relative: top 100</div>