본문 바로가기
웹 프로그래밍 기초

[css] z-index

by oncerun 2022. 3. 11.
반응형

 

hammer.js를 사용해 하이브리드 앱에 img의 확대/축소 기능을 개발했다. 

 

문제가 하나 발생했는데, 이미지가 여러 개 생성되다 보니 확대 시 다른 이미지의 레이어 위치가 확대한 이미지 위에 나오는 현상이 발생했다. 

 

<ion-col *ngFor="let img of checkItem.images">
	<img [src]="img.fileURL" style="width: 100%; height: 100%;" zoom-pan>
</ion-col>

 

ionic-col은 ionic 프레임워크의 태그이고  zoom-pan은 zoom기능을 속성 디렉티브로 정의했다.

 

화면 레이아웃상 문제라고 판단해 z-index에 대해서 좀 자세히 알아보고 자바스크립트로 해당 DOM객체의 z-index를 이벤트에 따라 조정하면 문제가 해결될 것이라고 판단했다. 

 

z-index가 없는 경우 쌓임.

 

모든 엘리먼트들에 z-index가 지정되지 않았을 경우에는 엘리먼트들이 다름 순서로 아래에서부터 위로 쌓인다.

 

1. 루트 엘리먼트의 배경과 테두리

2. 자식 엘리먼트들은 HTML에 등장하는 순서대로

3. position이 지정된 자식 엘리먼트들은 HTML에서 등장하는 순서대로

 

현재 img태그는 HTML 등장하는 대로 쌓이는 것으로 보인다. 

만약 3개의 이미지가 <ion-col> 태그에 감싸져 있는 경우 3번째 이미지를 확대했을 경우에는 아무런 이상이 없다.

 

만약 position 속성이 존재하지 않는 엘리먼트는 항상 postion이 지정된 엘리먼트 이전에 렌더링 된다. 따라서 postion이 이 지정된 엘리먼트 하위에 존재하게 된다. 설령 HTML 문서상에서 먼저 나오더라도 postion이 지정되지 않은 엘리먼트는 지정된 엘리먼트보다 아래에 보인다.

 

이를 통해 실험을 하기로 했다. img태그는 postion속성이 존재하지 않기 때문에 사용자가 확대 및 축소 이벤트를 시작하는 경우 해당 img태그에 postion속성 값을 부여하고 scale 값이 1 이하인 경우에 postion을 삭제하는 방식이다.

 

그럼 어떤 position을 주어야할까?

 

static : 기본값, z-index 속성이 영향을 주지 않음.

relative : 페이지 레이아웃에서 요소가 차지하는 공간은 static일 때와 같음. 

 

absolute, fixed, sticky를 고려할 필요는 없어 보이고, relative로 선택했다.

 

position을 주는 방법을 정했기에 해제하는 방법도 알아야 한다. 

부모가 position이 없으니 inherit으로 속성 값 상속받아 처리하는 걸로 했다.

            if (ev.type === 'pinch') {
                el.style.postion = 'relative';
                el.style.zIndex = 3;
                scale = Math.max(.999, Math.min(last_scale * (ev.scale), 4));
            }

 

pinch 이벤트인 경우 엘리먼트의 postion과 zIndex값을 수정하였다. 

 

            if(scale <= 1.3){
              el.style.position = 'inherit';
              el.style.zIndex = 1;
            }

이벤트에 따른 scale 값이 1.3 이하인 경우 zIndex와 postion값을 초기화시켰다.

 

성공이다.

 

[PS] 애뮬레이터 터치 위치 중앙에만 뜨는데 이동하면서 터치하는 법 아시는 분..

 

 

추가적으로 z-index를 적용시키는 법을 알아보자.

 

기본적으로  엘리먼트들이 어떻게 쌓이는지 보았다. 루트, 자식 등장, postion... 

만약 별도의 쌓임 순서를 지정하려면 엘리먼트에 postion속성과 z-index속성을 지정해야 한다.

 

z-index 속성은 하나의 정수 값을 가지며 양수, 음수 모두 가능하다. 이 값은 사용자 위치의 가상의 z 축 상의 위치를 나타낸다. 

 

z-index속성은 사실 position 속성이 설정된 엘리먼트에 대해서만 동작한다고 경고한다. 따라서 position과 z-index를 순차적으로 적용시킨 위의 경우가 러키였다. 

 

기본 값은 기본 렌더링 레이어에 렌더링 된다고 한다.  이는 0을 의미한다.

 

 

그럼 stacking context도 알아보자. 

 

개발자에게 행운이란 존재해선 감사하다. 하지만 이는 정확한 해결방법이 아닐 수도 있고, 매번 운이 따를 수 없다. 가장 중요한 건 나 자신이 확신 없는 모든 코드는 무서워서...

 

쌓임 맥락이라고 한다. 이는 가상의 z 축을 사용한 HTML 요소의 3차원 개념화이다. 

우리가 지금 웹페이지를 바라보는 그 거리를 z 축이라고 하는 것 같다.

 

쌓임 맥락은 다음 조건을 만족하는 요소가 생성된다고 한다.  이전에 알아본 것보다 더 많은 예시가 있다.

  • 문서의 루트 요소. (<html>)
  • position이 absolute 또는 relative이고, z-index가 auto가 아닌 요소. 
  • position이 fixed 또는 sticky인 요소. (sticky는 모든 모바일 브라우저에서는 해당하지만 구형 데스크톱 브라우저에서는 해당하지 않음)
  • 플렉스(flexbox) 컨테이너의 자식 중 z-index가 auto가 아닌 요소.
  • 그리드(grid) 컨테이너의 자식 중 z-index가 auto가 아닌 요소.  (미안 그리드는 아직..)
  • opacity가 1보다 작은 요소. 
  • mix-blend-mode가 normal이 아닌 요소.
  • 다음 속성 중 하나라도 none이 아닌 값을 가진 요소.
    • transform
    • filter
    • perspective 
    • clip-path
    • mask / mask-image (/ mask-border 
  • isolation이 isolate인 요소.
  • -webkit-overflow-scrolling이 touch인 요소.
  • will-change의 값으로, 초깃값이 아닐 때 새로운 쌓임 맥락을 생성하는 속성을 지정한 요소.
  • contain이 layout, paint, 또는 둘 중 하나를 포함하는 값(strict, content 등)인 요소.

 

 

 

이 조건중 아마 position이 가장 상위에 쌓이는 조건으로 보이며 나머지는 렌더링 되는 순서를 따르는 것 같다. 

 

 

중요한 점 있는 것 같다.

 

stacking context는 다른 stacking context를 포함할 수 있고, 함께 계층 구조를 이룬다.

 

형제 쌓임 맥락과 완전히 분리된다. 즉 자손 요소만 고려한다. 이건 중요하다.!! 


결국 루트로부터 쌓이는데 형제로 나누어진 경우 별도의 쌓임 맥락이 적용되고 이는 z-index 또한 형제 요소들 간에는 적용이 안된다고 봐야 하는 걸까?

 

각각의 쌓임 맥락은 독립적입니다. 

 

계층 구조

  • 루트
    • DIV #1
    • DIV #2
    • DIV #3
      • DIV #4
      • DIV #5
      • DIV #6

다음 예시를 통해 조금 더 이해해보자. 

 

DIV#4는 z-index값이 6이다. DIV#1의 z-index값은 5이다. 그럼 왜 DIV#1이 상위에 쌓여있을까?

 

아까 내가 가진 의문점이 해결되는 순간이다.  그 이유는 DIV#1의 z-index 속성 값인 5는 루트 엘리먼트의 쌓임 맥락 안에서 유효하나 DIV#4의 z-index 속성 값인 6은 DIV#3의 쌓임 맥락 안에서만 유효하기 때문이다.  

 

이는 z-index으로 z 축 조절을 위해서는 동일 부모에서의 쌓임 맥락이 필요하다는 것이다. 

 

  • 렌더링 순서를 이해하는 쉬운 방법은 z-index를 "버전 번호"처럼 생각하는 것이다. 자식 엘리먼트는 부모 엘리먼트 버전 번호의 마이너 버전이다. 이 방법은 왜 z-index가 1인 DIV #5가 z-index가 2인 DIV #2 위에 쌓였는지, z-index가 6인 DIV #4가 z-index가 5인 DIV #1 아래에 쌓였는지 이해하게 해 준다. 우리 예제에서는
    • 뿌리 엘리먼트
      • DIV #2 - z-index가 2
      • DIV #3 - z-index가 4
        • DIV #5 - z-index가 1인데 z-index가 4인 엘리먼트 아래에서 쌓였으므로 렌더링 순서는 4.1이다.
        • DIV #6 - z-index가 3인데 z-index가 4인 엘리먼트 아래에서 쌓였으므로 렌더링 순서는 4.3이다.
        • DIV #4 - z-index가 6인데 z-index가 4인 엘리먼트 아래에서 쌓였으므로 렌더링 순서는 4.6이다.
      • DIV #1 - z-index가 5

 

 

MDN의 설명은 참 잘 돼있는 것 같다.  마이너 버전으로 이해하니 좀 더 직관적으로 이해가 쉽다. 

문제 해결 끗

반응형

'웹 프로그래밍 기초' 카테고리의 다른 글

DOM (1)  (0) 2022.03.12
브라우저의 렌더링 과정  (0) 2022.03.11
Canvas  (0) 2021.10.17
파일 다운로드 회고  (2) 2021.09.08
주요 웹 서버  (0) 2021.07.06

댓글