CSS float 과 overflow / clear fix (내부플로팅 문제해결)

mh·2021년 11월 6일
1

5일차 수업시간에 네XX 로그인창 UI 만들기 실습을 했었는데
나 혼자 너무 헤멘것 같아서 따로 연습해 보았다.


1. 로그인 창 살펴보기


이렇게 생겼다..
크게 나눠본다면
요렇게 3개 구획으로 나뉠것 같다.

제일 아래쪽 아이디 · 비밀번호찾기 회원가입 구획을 단순하게 나타내면...

일단 요걸 만들어 보기로 하고 연습을 해봤다.

2. 요소 배치하기


<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>positionstudy</title>
</head>

    <style>

        .one{
            background: rgb(141, 95, 160);
            border: 2px solid rgb(48, 48, 48);
            clear: both;
        }

        .two{
            margin: 50px 50px 50px 50px;
            background: rgb(255, 203, 91);
            border: 1px dotted rgb(22, 22, 22);
            clear: both;
        }

        .three{
            width: 200px;
            height: 200px;
            background: rgb(44, 211, 155);
        }

        .four{
            width: 200px;
            height: 200px;
            background: rgb(253, 121, 59);
        }
    
    </style>

<body>
    <div class="one">
        <div class="two">
            <div class="three"></div>
            <div class="four"></div>
        </div>
    </div>
</body>
</html>


크게 감싸는 상자(one) 그안에 들어있는 상자(two) 그리고 그안에 요소 둘(three,four)을 배치해보았다.

3. float을 이용해 가로로 정렬하기



블록요소를 배치했을때 거꾸로 쌓이는 테트리스 처럼 위에서 아래로 흐르는 방향을 normal flow라고 한다.

이때 요소에 float을 부여하면 normal flow를 벗어나 float을 부여받은 요소들 끼리 Left냐 Right냐에 따라 가로로 정렬이 가능하다.

위의 class="two"색깔을 노란색으로 바꾸고 flaot:left;를 부여해보자 한칸이 사라졌다... 어디로간걸까

그렇다면 float:right; 을 사용해보자사라진 .three가 보인다 즉 one에 three부터 끝까지 달라붙어 있고 .two는 자신의 원래위치(.one의 아래쪽)의 오른쪽에서 다시 정렬을 시작하는 것을 알 수 있다. 말 그대로 떠있는(float)것이다.
여기서 .three 에도 float:right을 부여하면.. 이렇게 .two에 가서 붙게된다.
여기서 .six에 float:right을 부여하면 .three에 가서 붙게될까?
이럴수가 아니였다. 본래 자신의 위치에서 오른쪽으로 바뀔 뿐이였다.
그렇다면 .five에 주면 어떨까

복잡한 모양이 되었지만 바로위에 있는 .two와 .three 처럼 순서대로 .five .six 순서대로 정렬되었다. 내친김에 .four도 float시켜보자
요렇게 오른쪽으로 잘 달라붙어서 정렬되었다!

이해를 돕기위해 강사님이 보내주신 이미지... 이때 float과 position은 레이어라기 보다는 다른차원(?) 이라고 한다.

4. overflow / clear & clear-fix



다시 이상태에서 three 와 four에 각각 float:left와 float:right를 적용시키면 원하는 모양을 만들 수 있을 것이다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>positionstudy</title>
</head>

    <style>

        .one{
            background: rgb(141, 95, 160);
            border: 2px solid rgb(48, 48, 48);
            clear: both;
        }

        .two{
            margin: 50px 50px 50px 50px;
            background: rgb(255, 203, 91);
            border: 1px dotted rgb(22, 22, 22);
            clear: both;
        }

        .three{
            float: left;
            width: 200px;
            height: 200px;
            background: rgb(44, 211, 155);
        }

        .four{
            float:right;
            width: 200px;
            height: 200px;
            background: rgb(253, 121, 59);
        }
        
    </style>
    
<body>
    <div class="one">
        <div class="two">
            <div class="three"></div>
            <div class="four"></div>
        </div>
    </div>
</body>
</html>

엥?

🎯 왜 이렇게 되는 것일까?

three와 four의 부모가 되는 two는 너비(width)와 높이(height)가 없다.
그러므로 three와 four가 차지하는 만큼만 너비와 높이를 가지게 된다.
그렇기 때문에 three four가 flaot속성을 부여받는 순간 three와 four가 떠버리고 두 요소가 차지하는 공간은 0이 되어버린다. 그러므로 two는 0의 넓이를 가지게 되어 점선(border dotted 1px) 밖에 보이지 않게된다.

슬프게도 부모요소인 two가 float된 자식요소인 three와 four를 찾지 못하는 것이다.😭
two의 자식인 three와 four를 찾아주는 방법은 3가지가 있다.

1. 높이(height)값을 지정해주기 (권장되지 않음)

이 방법은 자식개체의 높이만큼 부모개체의 높이를 지정해주는 것이다.
하지만 자식개체의 값이 유동적으로 변하거나 새로운 자식 요소의 추가 또는 수정이 불편하기 때문에 스태틱한 요소가 아니면 권장하지 않는 방법이라고 한다.

📝지금 생각해보니 이것때문에 수업시간에 굉장히 헤멘것 같다. 부모요소의 값을 지정해두고 자식개체의 값을 수정하려고 하니 마진값도 안먹고 모양도 이상해지고...앞으로는 자식개체부터 확실히 해놓은 다음에 부모개체를 수정해야겠다.

2. overflow 적용하기

Overflow는 넘치는 속성을 감지하는 역할을 하기 때문에 이 속성이 적용된 부모개체는 float속성인 자식요소들도 감지할 수 있게 된다.

MDN Web Docs | Overflow
MDN Web Docs | Block format context
블록 서식 맥락(block format context)은 웹 페이지를 렌더링하는 시각적 CSS의 일부로서, 블록 박스의 레이아웃이 발생하는 지점과 플로팅 요소의 상호작용 범위를 결정하는 범위입니다.

또한 overflow속성은 기본속성인 visible을 제외하고 새로운 블록 서식문맥(flow)을 생성한다.
즉, 다시한번 감싸는(wrap) 효과를 얻게 된다!

  • overflow: visible;
    오버플로우를 안줬을때랑 똑같은 기본속성인 것 같다. 블록서식을 작성하지 아니하며 이미지를 자르지도 않고 넘친 내용들을 그대로 보여준다.

    .two{ overflow: visible; }

    참고로 밑에서 다룰 display:flow-root;를 같이 사용하면 블록서식문맥을 생성하기 때문에 아래와 같은 결과물을 얻을 수 있다.

  • overflow: hidden;
    내용물을 안쪽 컨테이너 상자에 맞춰 잘라준다. 스크롤 바를 제공하지 않으며 이상태에서 스크롤할 방법(마우스 드래그 또는 마우스 휠)도 지원하지 않는다. 자바스크립트의 scrollTop이나 offsetLeft를 이용해서 스크롤이 가능하다고 하며 이상태의 컨테이너는 스크롤 컨테이너로 취급한다고 한다. 새로운 서식문맥을 작성한다.

    .two{overflow:hidden;}

  • overflow: clip; (🧪실험실)
    hidden과 마찬가지로 컨테이너박스에 맞추어 자르지만 새로운 문맥을 생성하지도 않고 hidden과는 다르게 어떠한 방법으로도 스크롤이 불가능하며 스크롤 컨테이너도 아니다. 서식문맥이 필요하다면 display:flow-root;로 서식문맥을 제공 할 수 있다고 한다.

    MDN Web Docs | 내부 플로팅 가두기 예제
    MDN 웹 문서에 내부 플로팅을 가두는 여러가지 방법들에 대해서 기술되어 있다.
    그중에 display:flow-root;도 포함되어 있는데 각종 골치아픈 문제없이 블록서식문맥을 생성해주는 새로운 display 속성이라고한다.

    .two{overflow:clip;}

    .two{overflow:clip;
         display:flow-root;}

  • overflow:scroll;
    콘텐츠를 여백 컨테이너에 맞춰 잘라내고, 잘린만큼 말 그대로 스크롤바를 달아줘 이동이 가능하게 해준다. 내용물이 잘렸던 잘리지 않았던 스크롤바는 무조건 표기하며, 프린터 인쇄시에는 컴퓨터가 넘친 이미지를 인쇄 할 수도 있다고 한다.
    .two{overflow:scroll;

  • overflow:auto;
    사용자 에이전트 즉,브라우저에게 판단을 맡긴다. 컨테이너안의 요소가 넘치지 않았다면 visible;과 동일한 모습을 보이지만 새로운 서식문맥을 생성한다는 차이점이 있다. 요소가 넘쳤을 경우에는 컨테이너에 맞춰 잘라내고 스크롤을 자동생성한다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>positionstudy</title>
</head>

    <style>

        .one{
            background: rgb(141, 95, 160);
            border: 2px solid rgb(48, 48, 48);
            clear: both;
        }

        .two{
            height: 200px;
            overflow: auto;
            margin: 50px 50px 50px 50px;
            background: rgb(255, 203, 91);
            border: 1px dotted rgb(22, 22, 22);
            clear: both;
        }

        .three{
            float: left;
            width: 400px;
            height: 400px;
            background: rgb(44, 211, 155);
        }

        .four{
            float:right;
            width: 200px;
            height: 200px;
            background: rgb(253, 121, 59);
        }
        
    </style>

<body>
    
    <div class="one">
        <div class="two">
            <div class="three"></div>
            <div class="four"></div>
        </div>
    </div>



</body>
</html>

3.clear 속성 적용하기

clear 속성은 요소 앞에있는 플로팅(float)요소 아래로 요소를 이동(또는 제거clear)해야하는지 여부를 설정하는 속성이다.

MDN Web Docs | CSS clear
When applied to non-floating blocks, it moves the border edge of the element down until it is below the margin edge of all relevant floats. The non-floated block's top margin collapses.

해석해보면, float속성을 지니지 않은 블럭요소에 적용될 시, 요소의 가장자리를 관련되어있는 float속성을 가진 요소의 가장 아래까지 이동시킨다고 되어있다.

이를 이용해 float속성을 지니지 않으면서 .three .four에 관련된, 즉 .two안에 새로운 float하지 않는 형제요소를 만들어주고 여기에 clear속성을 부여해 줌으로서, 이 요소의 가장자리를 .three .four의 가장자리만큼 늘리고 부모개체인 .two는 float 되지 않은 이 요소를 감지해서 hegith를 인식하면 우리가 원하는 모양을 만들 수 있다.
정리해보면
1. two 안에 .threefour의 새로운 형제(관련된)요소가 될 빈 요소를 하나 만들어준다 ex) <div class="clear"></div>
2..clear는 float 되지 않는 상태에서 clear속성을 받는 블럭요소여야한다. 또한 left와 right 양쪽 모두에 float된 요소가 있기 때문에 방향은 both로 .clear{ display:block;(블럭요소가 아닐경우 ex가상선택자) clear:both;}
3. 이렇게 되면 빈 요소인 .clear는 float이 아니기 때문에 .two가 감지할 수 있고, height는 .three .four의 값인 200px에 맞춰지게 된다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>positionstudy</title>
</head>

    <style>

        .one{
            background: rgb(141, 95, 160);
            border: 2px solid rgb(48, 48, 48);
            clear: both;
        }

        .two{
            margin: 50px 50px 50px 50px;
            background: rgb(255, 203, 91);
            border: 1px dotted rgb(22, 22, 22);
            clear: both;
        }

        .three{
            float: left;
            width: 200px;
            height: 200px;
            background: rgb(44, 211, 155);
        }

        .four{
            float:right;
            width: 200px;
            height: 200px;
            background: rgb(253, 121, 59);
        }

        
        .clear{
            clear: both;
        }
    </style>

<body>
    
    <div class="one">
        <div class="two">
            <!-- <div class="clear"></div> -->
            <div class="three"></div>
            <!-- <div class="clear"></div> -->
            <div class="four"></div>
            <div class="clear"></div>
            
        </div>
    </div>



</body>
</html>


이 때 반드시 클리어 속성을 가진 요소는 컨테이너 내부요소의 가장 끝단을 파악하기 위해 다른 요소 중 가장 마지막에 와야한다.

  1. 가장 첫번째에 올 경우
    자신의 앞에 아무요소도 없으므로 아무것도 감지하지 못하고 0이 되어버린다.

  2. .three 다음 왔을 경우(두번째로 왔을경우)
    이번엔 앞에 있는 .three 감지해서 200px의 내부컨테이너를 형성했지만 .four는 감지하지 못한채로 상자바깥으로 빠져나왔다.

요소 맨 뒤로 와야 하는 이러한 특성을 이용하여
after가상요소선택자를 이용하는 방법도 있다. 이를 clear fix 라고 부른다고 한다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>positionstudy</title>
</head>

    <style>

        .one{
            background: rgb(141, 95, 160);
            border: 2px solid rgb(48, 48, 48);
            clear: both;
        }

        .two{
            margin: 50px 50px 50px 50px;
            background: rgb(255, 203, 91);
            border: 1px dotted rgb(22, 22, 22);
            clear: both;
        }

        .three{
            float: left;
            width: 200px;
            height: 200px;
            background: rgb(44, 211, 155);
        }

        .four{
            float:right;
            width: 200px;
            height: 200px;
            background: rgb(253, 121, 59);
        }
        
        .two::after{
            display: block;
            content:'';
            clear: both;
        }


    </style>

<body>
    
    <div class="one">
        <div class="two">
            <div class="three"></div>

            <div class="four"></div>
        </div>
    </div>



</body>
</html>

이러면 요소도 더 추가하기 편리하다.


최종적으로 맨 위에 계획했던 모습과 같은 구조의 컨테이너를 얻게 되었다!


마치며..

이 포스트를 쓰면서 MDN문서를 정말 꼼꼼하게 보게되었다. 예전에는 그냥 수업시간에 흝어보고 예제만 스윽 보기만했는데,
MDN문서는 정말 내용을 필요한 것만 모아논 집약체라 중요하지 않은 문단이 없는 것 같다. 간단해 보이는 내용도 토씨하나라도 놓지지 않고 읽어야 온전히 내것으로 쓸 수 있는 것 같다. (그전에 제대로 안읽으니 작동을 하지 않는것이였다ㅋㅋ)

profile
🤪🤪🤪🤪🤪

0개의 댓글