CSS의 최고 계층 항목 및 디스플레이 속성 전환-Smashing Magazine

CSS의 최고 계층 항목 및 디스플레이 속성 전환-Smashing Magazine

애니메이션에서 display: none; 수업을 변경하거나 다른 해킹을 만들기 위해 JavaScript만으로 달성 할 수있는 것입니다. CSS 에서이 작업을 수행 할 수없는 이유는 새로운 CSS 전환 레벨 2 사양에 설명되어 있습니다.

“이 사양의 레벨 1에서 전환은 이전 스타일 변경 이벤트에 의해 설정된 변화 전 스타일을 가진 요소에 대한 스타일 변경 이벤트에서만 시작할 수 있습니다. 즉, 이전 스타일 변경 이벤트를 위해 렌더링되지 않은 요소에 대한 전환이 시작될 수 없습니다.”

간단히 말해서, 이것은 우리가 숨겨져 있거나 방금 만들어진 요소에 대한 전환을 시작할 수 없음을 의미합니다.

무엇을 하는가 transition-behavior: allow-discrete 하다?

allow-discrete CSS 속성 값에 대한 약간 이상한 이름이 맞습니까? 우리는 전환에 대해 계속하고 있습니다 display: none그래서 왜 이것이 이름이 없습니다 transition-behavior: allow-display 대신에? 그 이유는 이것이 CSS를 처리하는 것보다 조금 더 작용하기 때문입니다. display CSS에는 다른 “이산”속성이 있기 때문에 속성. 간단한 경험 법칙은 개별 속성이 전환되지 않고 일반적으로 두 상태 사이에서 바로 뒤집는 것입니다. 이산 특성의 다른 예는 다음과 같습니다 visibility 그리고 mix-blend-mode. 이 기사의 끝에 이들의 예를 포함하겠습니다.

요약하기 위해 transition-behavior 속성 allow-discrete 브라우저에 개별 속성의 값을 교환 할 수 있다고 말할 수 있습니다 (예 : display,,, visibility그리고 mix-blend-mode) 전환의 0% 마크 대신 50% 마크에서.

무엇을 하는가 @starting-style 하다?

그만큼 @starting-style 규칙은 페이지로 렌더링되기 직전에 요소의 스타일을 정의합니다. 이것은 함께 고도로 필요합니다 transition-behavior 그리고 이것이 이유입니다.

항목이 DOM에 추가되거나 처음에 display: none전환에 필요한 일종의 “시작 스타일”이 필요합니다. 예제를 더하려면 팝 오버 및 대화 요소가 문서 흐름 외부의 레이어 인 상단 레이어에 추가됩니다. element in your page’s structure. Now, when opening this dialog or popover, they get created inside that top layer, so they don’t have any styles to start transitioning from, which is why we set @starting-style. 이 모든 것이 약간 혼란스러워지면 걱정하지 마십시오. 데모는 더 명확하게 만들 수 있습니다. 알아야 할 중요한 점은 브라우저에 애니메이션을 시작할 수있는 무언가를 제공 할 수 있다는 것입니다. 그렇지 않으면 애니메이션이 없기 때문입니다.

브라우저 지원에 대한 메모

글을 쓰는 순간에 transition-behavior Chrome, Edge, Safari 및 Firefox에서 제공됩니다. 그것은 동일합니다 @starting-style그러나 Firefox는 현재 애니메이션을 지원하지 않습니다 display: none. 그러나이 기사의 모든 것은 진보적 인 향상으로 완벽하게 사용될 수 있습니다.

이제 우리는 우리 뒤에있는이 모든 이론을 갖게되었으므로 실용적으로합시다. 이 기사에서 3 가지 사용 사례를 다룰 것입니다.

  • 애니메이션에서 display: none 돔에서.
  • 상단 계층에 들어가서 종료하는 애니메이션 대화 및 팝 오버.
  • 우리가 처리 할 수있는 더 많은 “이산 속성”.

애니메이션에서 display: none 돔에서

첫 번째 예는 살펴 보겠습니다 @starting-style 홀로. 나는이 데모를 순전히 마법을 설명하기 위해 만들었습니다. 페이지의 두 개의 버튼이 반지되지 않은 목록 내부의 목록 항목을 추가하거나 제거하려고한다고 상상해보십시오.

이것은 당신의 시작 HTML 일 수 있습니다 :




다음으로 해당 목록 항목을 추가하거나 제거하는 작업을 추가합니다. 이것은 당신이 선택한 방법 일 수 있지만 데모 목적으로, 나는 그것을 위해 약간의 JavaScript를 빨리 썼습니다.

document.addEventListener("DOMContentLoaded", () => {
  const addButton = document.querySelector(".btn-add");
  const removeButton = document.querySelector(".btn-remove");
  const list = document.querySelector('ul[role="list"]');

  addButton.addEventListener("click", () => {
    const newItem = document.createElement("li");
    list.appendChild(newItem);
  });

  removeButton.addEventListener("click", () => {
    if (list.lastElementChild) {
      list.lastElementChild.classList.add("removing");
      setTimeout(() => {
        list.removeChild(list.lastElementChild);
      }, 200);
    }
  });
});

클릭 할 때 addButton빈 목록 항목이 변하지 않은 목록 내에서 생성됩니다. 클릭 할 때 removeButton마지막 항목은 새 항목을 얻습니다 .removing 수업과 마침내 200ms 이후 DOM에서 꺼집니다.

이를 통해 우리는 항목에 대한 CSS를 작성하여 제거 부품을 애니메이션 할 수 있습니다.

ul {
    li {
      transition: opacity 0.2s, transform 0.2s;

      &.removing {
        opacity: 0;
        transform: translate(0, 50%);
      }
    }
  }

이것은 훌륭합니다! 우리의 .removing 애니메이션은 이미 완벽 해 보이지만, 여기서 우리가 찾고 있던 것은 DOM 내부에서 나오는 항목의 입구를 애니메이션하는 방법이었습니다. 이를 위해서는 시작 스타일과 목록 항목의 최종 상태를 정의해야합니다.

먼저, CSS를 업데이트하여 해당 목록 항목의 최종 상태를 갖도록하겠습니다.

ul {
    li {
      opacity: 1;
      transform: translate(0, 0);
      transition: opacity 0.2s, transform 0.2s;

      &.removing {
        opacity: 0;
        transform: translate(0, 50%);
      }
    }
  }

많이 바뀌지는 않았지만 이제는 브라우저에 시작 스타일이 무엇인지 알려주는 것은 우리에게 달려 있습니다. 우리는 이것을 우리와 같은 방식으로 설정할 수있었습니다. .removing 그렇게 같은 스타일 :

ul {
    li {
      opacity: 1;
      transform: translate(0, 0);
      transition: opacity 0.2s, transform 0.2s;

      @starting-style {
        opacity: 0;
        transform: translate(0, 50%);
      }

      &.removing {
        opacity: 0;
        transform: translate(0, 50%);
      }
    }
  }

이제 우리는 브라우저에게 그 사실을 알렸다 @starting-style 불투명도가 제로를 포함하고 transform. 최종 결과는 다음과 같습니다.

그러나 우리는 거기서 멈출 필요가 없습니다! 입력 및 종료에 다른 애니메이션을 사용할 수 있습니다. 예를 들어, 시작 스타일을 다음과 같이 업데이트 할 수 있습니다.

@starting-style {
  opacity: 0;
  transform: translate(0, -50%);
}

이렇게하면 상단에서 항목이 입력하여 하단으로 나옵니다. 이 CodePen의 전체 예를 참조하십시오.

펜을 참조하십시오 [@starting-style demo – up-in, down-out [forked]](유틸리티 벤드에 의해.

펜 @시작 스타일 데모 -UP-In, 다운 아웃을 참조하십시오 [forked] 유틸리티 벤드에 의해.

사용시기 transition-behavior: allow-discrete

이전 예에서는 DOM에서 항목을 추가하고 제거했습니다. 다음 데모에서는 CSS를 사용하여 항목을 보여주고 숨길 것입니다. display 재산. 기본 설정은 8 개의 목록 항목을 DOM에 추가하는 것을 제외하고는 거의 동일합니다. .hidden 그것에 첨부 된 클래스 :

  
  


다시 한번, 데모 목적으로, 나는 이번에는 약간의 JavaScript를 추가했습니다. .hidden 다음 항목의 클래스를 클릭 할 때 addButton 그리고 추가합니다 hidden 클릭을 클릭 할 때 다시 수업 removeButton:

document.addEventListener("DOMContentLoaded", () => {
  const addButton = document.querySelector(".btn-add");
  const removeButton = document.querySelector(".btn-remove");
  const listItems = document.querySelectorAll('ul[role="list"] li');

  let activeCount = 0;

  addButton.addEventListener("click", () => {
    if (activeCount  {
    if (activeCount > 0) {
      activeCount--;
      listItems[activeCount].classList.add("hidden");
    }
  });
});

우리가 지금까지 배운 모든 것을 모아서 추가하겠습니다. @starting-style 우리의 항목에, 그리고 CSS에서 기본 설정을 수행하십시오.

ul {
    li {
      display: block;
      opacity: 1;
      transform: translate(0, 0);
      transition: opacity 0.2s, transform 0.2s;

      @starting-style {
        opacity: 0;
        transform: translate(0, -50%);
      }

      &.hidden {
        display: none;
        opacity: 0;
        transform: translate(0, 50%);
      }
    }
  }

이번에는 다음을 추가했습니다 .hidden 클래스를 설정하십시오 display: none동일하게 추가했습니다 opacity 그리고 transform 우리가 이전에했던 것처럼 선언 .removing 마지막 예에서 수업. 예상대로, 우리는 품목에 대한 멋진 페이드 인을 얻지 만, 우리는 품목을 직접 설정할 때 여전히 갑작 스럽습니다. display: none.

이것은 어디에 있습니다 transition-behavior 부동산이 작용합니다. 조금 더 분해하려면 transition 이전 CSS의 속성 속성 및 조금 열립니다.

ul {
    li {
      display: block;
      opacity: 1;
      transform: translate(0, 0);
      transition-property: opacity, transform;
      transition-duration: 0.2s;
    }
  }

남은 것은 전환뿐입니다 display 속성을 설정하고 설정하십시오 transition-behavior 속성 allow-discrete:

ul {
    li {
      display: block;
      opacity: 1;
      transform: translate(0, 0);
      transition-property: opacity, transform, display;
      transition-duration: 0.2s;
      transition-behavior: allow-discrete;
      /* etc. */
    }
  }

우리는 이제 요소를 애니메이션하고 있습니다 display: none그리고 결과는 우리가 원하는대로 정확히 다음과 같습니다.

우리는 사용할 수 있습니다 transition 우리의 코드를 조금 덜 장황하게 만드는 속성 속성 :

transition: opacity 0.2s, transform 0.2s, display 0.2s allow-discrete;

당신은 추가 할 수 있습니다 allow-discrete 거기에. 그러나 그렇게한다면, 속기 전환을 선언하면 transition-behavior그것은 무효화 될 것입니다. 따라서 이것 대신 :

transition-behavior: allow-discrete;
transition: opacity 0.2s, transform 0.2s, display 0.2s;

… 우리는 선언하고 싶습니다 transition-behavior ~ 후에 그만큼 transition 속기:

transition: opacity 0.2s, transform 0.2s, display 0.2s;
transition-behavior: allow-discrete;

그렇지 않으면 transition 속성 속성이 무시됩니다 transition-behavior.

펜을 참조하십시오 [@starting-style and transition-behavior: allow-discrete [forked]](유틸리티 벤드에 의해.

펜 @시작 스타일 및 전환-행동 : 허용-디스 크레타를 참조하십시오 [forked] 유틸리티 벤드에 의해.

상단 레이어에 들어가서 종료하는 애니메이션 대화 상자 및 팝 오버

대화 상자와 팝 오버가있는 몇 가지 사용 사례를 추가해 봅시다. 대화 상자와 팝 오버는 열 때 상단 레이어에 추가되기 때문에 좋은 예입니다.

그 최고 레이어는 무엇입니까?

우리는 이미“최상층”을 형제에 비유했습니다. element, but you might also think of it as a special layer that sits above everything else on a web page. It’s like a transparent sheet that you can place over a drawing. Anything you draw on that sheet will be visible on top of the original drawing.

The original drawing, in this example, is the DOM. This means that the top layer is out of the document flow, which provides us with a few benefits. For example, as I stated before, dialogs and popovers are added to this top layer, and that makes perfect sense because they should always be on top of everything else. No more z-index: 9999!

그러나 그 이상입니다.

  • z-index 관련이 없습니다: 상단 레이어의 요소는 항상 상단에 있습니다. z-index 값.
  • Dom 계층은 중요하지 않습니다: DOM의 요소 위치는 상단 레이어의 스태킹 순서에 영향을 미치지 않습니다.
  • 배경: 우리는 새로운 것에 접근 할 수 있습니다 ::backdrop 상단 층과 그 아래의 돔 사이의 영역을 스타일링 할 수있는 의사 요소.

바라건대, 당신은 상단 계층의 중요성과 우리가 팝 오버와 대화와 마찬가지로 요소를 전환 할 수있는 방법을 이해하기 시작했습니다.

상단 계층에서 대화 요소를 전환합니다

다음 HTML에는 a에 열리는 버튼이 포함되어 있습니다

요소 요소에는 다음을 닫는 다른 버튼이 포함되어 있습니다 . 따라서, 우리는 하나의 버튼이 있습니다 그리고 그것을 닫는 하나.




  

Hi, there!

HTML에서 다음 단계를 좀 더 쉽게 만들 수있는 Invoker 명령과 함께 많은 일이 발생하지만 지금은이 모달을 실제로 작동시키기 위해 약간의 JavaScript를 추가해 봅시다.

// Get all open dialog buttons.
const openButtons = document.querySelectorAll(".open-dialog");
// Get all close dialog buttons.
const closeButtons = document.querySelectorAll(".close-dialog");

// Add click event listeners to open buttons.
openButtons.forEach((button) =

다음 스타일을 시작점으로 사용하고 있습니다. 내가 어떻게 스타일링하는지 주목하십시오 ::backdrop 추가 보너스로!

dialog {
  padding: 30px;
  width: 100%;
  max-width: 600px;
  background: #fff;
  border-radius: 8px;
  border: 0;
  box-shadow: 
    rgba(0, 0, 0, 0.3) 0px 19px 38px,
    rgba(0, 0, 0, 0.22) 0px 15px 12px;
    
  &::backdrop {
    background-image: linear-gradient(
      45deg in oklab,
      oklch(80% 0.4 222) 0%,
      oklch(35% 0.5 313) 100%
    );
  }
}

이로 인해 항목에 대한 매우 어려운 전환이 발생하여 매우 매끄럽지 않습니다.

이 대화 상자 요소와 배경에 전환을 추가합시다. 나는 이번에는 조금 더 빨리 갈 것입니다. 지금까지 패턴을보고 무슨 일이 일어나고 있는지 알기 때문입니다.

dialog {
  opacity: 0;
  translate: 0 30%;
  transition-property: opacity, translate, display;
  transition-duration: 0.8s;

  transition-behavior: allow-discrete;
  
  &[open] {
    opacity: 1;
    translate: 0 0;

    @starting-style {
      opacity: 0;
      translate: 0 -30%;
    }
  }
}

대화 상자가 열리면 브라우저가 삭감됩니다 open 그것에 속성 :

 ... 

그리고 그것은 우리가 CSS와 같이 타겟팅 할 수있는 다른 것입니다. dialog[open]. 따라서이 경우 a를 설정해야합니다 @starting-style 대화 상자가있을 때 open 상태.

우리가 그 동안 배경에 대한 전환을 추가합시다.

dialog {
  /* etc. */
  &::backdrop {
    opacity: 0;
    transition-property: opacity;
    transition-duration: 1s;
  }

  &[open] {
    /* etc. */
    &::backdrop {
      opacity: 0.8;

      @starting-style {
        opacity: 0;
      }
    }
  }
}

이제 당신은 아마도 생각하고 있습니다 : 아하! 그러나 당신은 그것을 추가했을 것입니다 display 속성과 transition-behavior: allow-discrete 배경!

그러나 아니요, 그렇지 않습니다. 배경 유사 요소를 다음 CSS로 변경하더라도 결과는 동일하게 유지됩니다.

 &::backdrop {
    opacity: 0;
    transition-property: opacity, display;
    transition-duration: 1s;
    transition-behavior: allow-discrete;
  }

우리는 a ::backdrop 그리고 함께 일할 때 ::backdrop우리는 또한 CSS와 함께 일하고 있습니다 overlay 상단 레이어에 나타나는 요소가 현재 상단 레이어로 렌더링되는지 여부를 지정하는 속성.

그리고 overlay 우리가 포함시켜야 할 또 다른 개별 속성이 있습니다. transition-property 선언:

dialog {
  /* etc. */

&::backdrop {
  transition-property: opacity, display, overlay;
  /* etc. */
}

불행히도, 이것은 현재 크롬 브라우저에서만 지원되지만 점진적인 향상으로 완벽하게 사용될 수 있습니다.

그리고 그렇습니다. 우리는 그것을 추가해야합니다 dialog 스타일도 :

dialog {
  transition-property: opacity, translate, display, overlay;
  /* etc. */

&::backdrop {
  transition-property: opacity, display, overlay;
  /* etc. */
}

펜을 참조하십시오 [Dialog: starting-style, transition-behavior, overlay [forked]](유틸리티 벤드에 의해.

펜 대화 상자 : 시작 스타일, 전환-행동, 오버레이를 참조하십시오 [forked] 유틸리티 벤드에 의해.

대화 상자 대신 팝 오버와 거의 같은 것입니다. 동일한 기술을 사용하고 있으며 이번에는 팝 오버로 만 작업하고 있습니다.

펜을 참조하십시오 [Popover transition with @starting-style [forked]](유틸리티 벤드에 의해.

@시작 스타일의 펜 팝 오버 전환을 참조하십시오 [forked] 유틸리티 벤드에 의해.

다른 개별 속성

우리가 여기에서 다루는 것 외에 몇 가지 다른 개별 속성이 있습니다. 두 번째 데모를 기억한다면 일부 항목을 display: none동일하게 달성 할 수 있습니다 visibility 대신 속성. 보이지 않더라도 요소 상자의 공간을 보존하려는 품목이 원하는 경우에 유용 할 수 있습니다.

따라서 여기와 같은 예제 만 사용합니다 visibility 대신 display.

펜을 참조하십시오 [Transitioning the visibility property [forked]](유틸리티 벤드에 의해.

가시성 속성을 전환하는 펜을 참조하십시오 [forked] 유틸리티 벤드에 의해.

CSS mix-blend-mode 재산은 개별로 간주되는 또 다른 재산입니다. 완전히 솔직히 말해서, 나는 데모를위한 좋은 사용 사례를 찾을 수 없습니다. 그러나 나는 계속해서 두 사람이 mix-blend-modes는 바로 전환 중간에 바로 전환합니다.

펜을 참조하십시오 [Transitioning mix-blend-mode [forked]](유틸리티 벤드에 의해.

펜 전환 믹스 블렌드 모드를 참조하십시오 [forked] 유틸리티 벤드에 의해.

마무리

그것은 우리가 최상위 계층 안팎에서 요소를 전환 할 수있는 방법에 대한 개요입니다! 이상적인 세상에서 우리는 transition-behavior 그렇지 않으면 “전환 할 수없는”속성을 전환하기 위해서는 우리가 여기 있습니다.

그러나 우리는 또한 배우게되었습니다 @starting-style 그리고 최상위 레이어에있는 요소의 전환 시작에 적용 할 수있는 스타일 세트를 브라우저에 제공하는 방법. 그렇지 않으면, 요소는 첫 번째 렌더에서 전환 할 것이 없으며, 상단 레이어 안팎에서 부드럽게 전환 할 수있는 방법이 없습니다.

스매싱 편집
(GG, YK)

출처 참조

Post Comment

당신은 놓쳤을 수도 있습니다