Float를 생성하면 부모요소(박스)의 패딩을 제외한 width만큼 Linebox가 생성된다.
float는 원래 레이아웃을 만들기 위한 용도로 나온 것이 아니었기 때문에, 그 특성에 의한 버그들을 처리하기 위해서 추가로 필요로 되는 작업들이 있다.
Normal flow(위에서 아래방향으로 차곡차곡 블럭이 쌓이는 것)을 float로 해제시키면 요소가 float로 인해서 3차원적인 방향으로 위로 뜨는 것과 같다. [ 이하 부유한다고 표현 ] 그렇기에 사용자들이 보기엔 float된 요소 아래로 기존의 박스요소가 겹쳐진 것 과 같은형태로 보이게 되는 것이다. (단 float된 요소는 text요소는 가리지를 못해서 자신의 영역만큼 텍스트를 밀어낸다.)
float를 설정해주면서 width값을 지정해 주지 않았다면, 자동으로 박스내부의 컨텐츠의 넓이만큼으로 크기가 설정되어 부유된다. 부유되면 부모영역(부모박스)가 자식영역(자식박스)가 가지고 있던 height값을 잃어버리게 된다. (내부에 text를 가지고 있을 경우에는 text가 가진 width값 만큼만을 가지고 위로 떠버리는 형태이기 때문에 공중에 떠있으므로, 더이상 부모요소가 포함하고 있는 요소가 아니게 되기 때문이다.) 이로 인하여 레이아웃 무너짐이 발생하기 쉽다.
해결방법들
float된 요소 다음으로 오는 요소 박스들에 clear:both를 지정해주면 float의 영향 밖에 자리를 잡게 된다. float와 겹침방지가 되는 것 처럼 동작하게 되는 것이다. (clear를 css동작원리를 내부적으로 본다면, float된 요소의 height값 만큼의 마진을 주는 것이다.) 단, 이는 형제레벨 요소 간의 float-clear일 경우이다.
위의 경우처럼 형제레벨 요소간의 float-clear가 아니라면 (ex: 상위요소의 자식요소(main내부의 .box1)과 main의 형제요소(footer)간의 float-clear관계는 마진 겹침 현상이 clear를 이용해도 발생하지 않는다.)
위의 그림에서 hello상자는 clear:both를 적용했고, clear속성에 의해서 내부적으로 hi상자 높이만큼인 20px을 margin-top으로 준 상태이기 때문에 추가로 margin-top을 20px을 적용했지만 변화가 없는 상황이다. 여기서 21px이상으로 margin-top을 적용하면 그때부터 위 float된 상자와 간격이 생기게 된다.
<다른 방법1>
overflow:hidden;
위의 속성을 이용하여 부모 박스 범위 밖으로 넘어간 float된 자식 요소들을 안보이게 하도록 한다.
이는 단순하게 넘어가는 영역을 보이지 않게 하기 위함이 아니다. overflow를 이용하면 부모요소가 잃어버린( 부모요소의 height:auto;일 경우) 자식요소의 height 값을 되찾아 올 수 있기 때문이다. overflow:(visible이외의 값) hidden, auto, scroll 등을 입력해 주면 독립적인 bfc영역을 생성한다. 쉽게 말하자면, overflow:hidden을 적용하기 위해서는 해당 박스요소의 정확한 영역을 알아야 하기 때문에 내부적으로 부모요소의 높이값인 auto를 결정짓는 자식요소의 height값을 되찾아 오게 된다. (부모요소의 높이가 auto이면 자식요소의 높이값을 가지고 자신의 높이로 하기 때문에..)
float되어서 알수없던 자식영역의 height값을 css내부적으로 다시 부모영역에 주게 되고, 이로 인해서 부모요소의 높이 값을 다시 그려서 보여주게 된다. ->단점: 너무 height값이 커서 부모영역 밖으로 나가버린 요소들이 hidden되어 보이지 않게 된다.
quiz) 위의 경우에, 부모박스의 min-height값에 값을 주면 해결이 되지 않을까?
A: min-height를 사용하면, 레이아웃 무너짐은 막으면서 컨텐츠의 height값이 증가하더라도 문제 없이 값이 같이 증가 할 수 있다. 그러나 이 경우에는 float된 자식 요소들이기 때문에 자식요소의 height값을 부모요소가 알 수 없게 되기 때문에, 부모요소의 min-height값 보다, float된 요소의 height값이 큰 경우는 영역 밖으로 벗어나는 문제가 생기게 된다.
참고: inline요소는 내부 컨텐츠의 값 이외의 height, width를 지정할 수 없다.(button태그 제외, button은 inline-block이다.)
<다른방법2> :가상요소 선택자를 이용한 방법(::after)->float속성을 적용한 요소의 부모요소에 적용해준다.
이 방법은 ::after라는 가상요소를 이용하는 것이다.(가장 권장되는 방법이다.) 가상요소는 가상의 요소를 만들어 출력한다. ::after와 ::before가 자주 사용된다. 이 방법을 사용하면 위의 clear:both만을 사용했을 때처럼 margin-top을 주어도 위의 플로트 된 형제요소 상자와의 마진 겹침 현상도 없다.
가상클래스(요소에 클래스를 부여하여, 요소의 상태에 따라 효과를 줄 때, 자주 사용되는 것들이다. 예를들어 :hover, :link등이 있다.)
위의 코드를 살펴 뜻을 보자. main태그 안의 자식요소 2가지가 각각 float:left;, float:right 적용이 되어있는 상황으로 본다. main태그에 가상요소::after를 적용해준다. 그렇게 하면 main요소 내부의 가장 마지막에 아무것도 포함하지 않은 익명의 상자가 생성되고, 이 상자는 inline요소이기 때문에 block으로 설정해주고 clear:both를 적용시켜 주는 것이다. 가상으로 생성된 요소인 익명의 상자 덕분에 그 다음으로 오는 내용들은 float에 영향을 받지 않고 제대로 배치될 수 있게 된다.
clear는 inline요소에는 적용이 되지 않는다. block요소에만 사용된다
위의 코드는 자주 사용하기 때문에 반복으로 또 작성하는 일이 없도록 유틸리티(재사용가능한 css덩어리들)화를 시켜서 사용가능하다.
(ex) nav::after{}, .box1::after{} , clearfix::after{}
::after로 만든 가상요소는 페이지에서 ctrl+a(전체선택)으로 잡히지 않는다. 따라서 javascript로 제어할 수 없다.
main::after{
Content:" ";/* 내부적으로 main의 마지막 자식요소로 익명의 텍스트 상자(anonymous text box)를 만든것->
이것이 clear속성을 갖게되어 main이 자식요소 높이를 찾은것 처럼 보인다. */
Clear:both; /* 클리어는 인라인에는 적용안되는데 Content는 inline이다. 따라서 아래처럼*/
Display:block; /* 강제로 block요소로 만든다.display:table;도 가능하다.*/
}