부모의 높이에 올바르게 영향을 미치는 CSS의 회전 된 요소


119

몇 개의 열이 있으며 그중 일부는 다음 값을 회전하고 싶습니다.

http://jsfiddle.net/MTyFP/1/

<div class="container">
    <div class="statusColumn"><span>Normal</span></div>
    <div class="statusColumn"><a>Normal</a></div>
    <div class="statusColumn"><b>Rotated</b></div>
    <div class="statusColumn"><abbr>Normal</abbr></div>
</div>

이 CSS로 :

.statusColumn b {
  writing-mode: tb-rl;
  white-space: nowrap;
  display: inline-block;
  overflow: visible;
  transform: rotate(-90deg);
  transform-origin: 50% 50%;
}

다음과 같이 보입니다.

일련의 4 개의 블록 수준 요소.  세 번째 요소의 텍스트가 회전됩니다.

회전 된 요소가 부모의 높이에 영향을 주어 텍스트가 다른 요소와 겹치지 않도록하는 CSS를 작성할 수 있습니까? 이 같은:

이제 세 번째 열의 텍스트가 상위 상자의 높이에 영향을 미치므로 텍스트가 상자 안에 맞습니다.


1
도움이 될 수 있습니다. stackoverflow.com/questions/7565542/…
Pete

7
쓰기 모드는 이제 대부분의 브라우저에서 사용할 수 있습니다 (IE5 기능 사용). 요즘에는 jsfiddle.net/MTyFP/698 참조 : developer.mozilla.org/en-US/docs/Web/CSS/writing-mode
G-Cyrillus

1
@ G-Cyr writing-mode는 대부분의 브라우저에서 사용할 수 있지만 끔찍하게 버그가 있습니다. 관련 질문에 대해 포기하기 전에 브라우저 관련 버그를 해결하려고 여러 번 반복했습니다. stackoverflow.com/posts/47857248/revisions 에서 연속적인 실패를 볼 수 있습니다 . 여기서 Chrome에서는 작동하지만 Firefox 또는 Edge에서는 작동하지 않는 것으로 시작한 다음 다른 두 가지를 수정하는 과정에서 Chrome을 중단하고 내 대답하고 Chrome 전용으로 레이블을 지정합니다. 이 길을 가고 싶다면 조심하십시오. (또한 텍스트가 아닌 요소와 아무 소용입니다 있습니다.)
마크 Amery에게

1
afaik 쓰기 모드는 텍스트에서만 작동합니다 ...
Fredrik Johansson

답변:


51

90도 회전을 원한다고 가정하면 텍스트가 아닌 요소의 경우에도 가능하지만 CSS의 많은 흥미로운 것들과 마찬가지로 약간의 교활함이 필요합니다. 내 솔루션은 기술적으로 CSS 2 사양에 따라 정의되지 않은 동작을 호출하므로 Chrome, Firefox, Safari 및 Edge에서 작동하는지 테스트하고 확인했지만 향후 중단되지 않을 것이라고 약속 할 수 없습니다. 브라우저 릴리스.

짧은 답변

이와 같은 HTML이 주어지면 회전하려는 위치 .element-to-rotate...

<div id="container">
  <something class="element-to-rotate">bla bla bla</something>
</div>

... 회전하려는 요소 주위에 두 개의 래퍼 요소를 소개 합니다.

<div id="container">
  <div class="rotation-wrapper-outer">
    <div class="rotation-wrapper-inner">
      <something class="element-to-rotate">bla bla bla</something>
    </div>    
  </div>
</div>

... 다음 CSS를 사용하여 시계 반대 방향으로 회전합니다 (또는 transform시계 방향 회전으로 변경하는 방법 은 주석 처리 된 내용 참조 ).

.rotation-wrapper-outer {
  display: table;
}
.rotation-wrapper-inner {
  padding: 50% 0;
  height: 0;
}
.element-to-rotate {
  display: block;
  transform-origin: top left;
  /* Note: for a CLOCKWISE rotation, use the commented-out
     transform instead of this one. */
  transform: rotate(-90deg) translate(-100%);
  /* transform: rotate(90deg) translate(0, -100%); */
  margin-top: -50%;

  /* Not vital, but possibly a good idea if the element you're rotating contains
     text and you want a single long vertical line of text and the pre-rotation
     width of your element is small enough that the text wraps: */
  white-space: nowrap;
}

스택 스 니펫 데모

어떻게 작동합니까?

위에서 사용한 주문에 대한 혼란은 합리적입니다. 많은 일이 진행되고 있으며 전반적인 전략은 간단하지 않으며 이해하려면 CSS 퀴즈에 대한 지식이 필요합니다. 단계별로 살펴 보겠습니다.

우리가 직면 한 문제의 핵심은 transformCSS 속성을 사용하여 요소에 적용된 변환이 모두 레이아웃이 발생한 후에 발생 한다는 것입니다. 즉, transform요소를 사용하더라도 부모 또는 다른 요소의 크기 나 위치에는 전혀 영향을주지 않습니다. transform작동 방식에 대한이 사실을 변경할 수있는 방법은 전혀 없습니다 . 따라서 요소를 회전하는 효과를 만들고 부모의 높이가 회전을 고려하도록하려면 다음을 수행해야합니다.

  1. 어떻게 든 높이가 너비와 같은 다른 요소를 구성 하십시오..element-to-rotate
  2. .element-to-rotate1 단계의 요소에 정확히 오버레이하도록 변환을 작성합니다 .

1 단계의 요소는 .rotation-wrapper-outer. 그러나 어떻게 그것의 높이.element-to-rotate'의 과 같게 만들 수 있습니까?

여기서 우리 전략의 핵심 요소는 padding: 50% 0on .rotation-wrapper-inner입니다. 이 익스플로잇 은 스펙의 특이한 세부 사항입니다.paddingpadding-toppadding-bottom에 대한 백분율 패딩 은 항상 요소 컨테이너 너비의 백분율로 정의됩니다 . 이를 통해 다음 2 단계 트릭을 수행 할 수 있습니다.

  1. 우리는 설정 display: table에서 .rotation-wrapper-outer. 이로 인해 너비맞게 축소 됩니다. 즉, 너비가 콘텐츠의 기본 너비 , 즉 기본 너비를 기반으로 설정됩니다 .element-to-rotate. (브라우저를 지원, 우리는 더 깨끗하게에이를 수 width: max-content, 12 월까지는 2017로 max-content되어 여전히 에지에서 지원되지 않습니다 .)
  2. 우리는 설정 height.rotation-wrapper-inner다음의 패딩 설정을 0 50% 0(이고, 50 %의 상위 50 % 아래). 이로 인해 부모 너비의 100 %에 해당하는 수직 공간을 차지하게됩니다. 1 단계의 트릭을 통해의 너비와 동일합니다 .element-to-rotate.

다음으로 남은 것은 자식 요소의 실제 회전 및 위치 지정을 수행하는 것입니다. 당연히 transform: rotate(-90deg)회전합니다. 우리 transform-origin: top left;는 회전 된 요소의 왼쪽 상단 모서리 주위에서 회전이 일어나도록하는데, 이것은 회전 된 요소가 다른 방법으로 그려졌을 위치 바로 위에 남겨지기 때문에 후속 변환을 더 쉽게 추론 할 수 있도록합니다. 그런 다음을 사용 translate(-100%)하여 회전 전 너비와 동일한 거리만큼 요소를 아래쪽으로 드래그 할 수 있습니다 .

에서 50 % 상단 패딩을 오프셋해야하기 때문에 여전히 올바른 위치를 얻지 못합니다 .rotation-wrapper-outer. 우리는 그 보장함으로써 그 달성 .element-to-rotatedisplay: block(그래서 마진이 제대로 작동합니다) 후 50 % 적용 margin-top비율 마진이 참고 - 또한 부모 요소의 너비를 기준으로 정의합니다.

그리고 그게 다야!

이것이 사양을 완전히 준수하지 않는 이유는 무엇입니까?

때문에의 사양에서 비율 패딩과 마진의 정의에서 다음 주 (굵은 글자 광산) :

백분율은 'padding-top''padding-bottom'의 경우에도 생성 된 상자의 포함 블록 너비 를 기준으로 계산됩니다 . 컨테 이닝 블록의 너비가이 요소에 의존하는 경우 결과 레이아웃은 CSS 2.1에서 정의되지 않습니다.

전체 트릭은 내부 래퍼 요소의 패딩이 자식의 너비에 따라 달라지는 컨테이너의 너비에 상대적이되도록하는 것이므로이 조건에 도달하고 정의되지 않은 동작을 호출합니다. 하지만 현재는 4 개의 주요 브라우저 모두에서 작동합니다. 겉보기에는 사양을 준수 하여 부모 대신 .rotation-wrapper-inner형제로 변경 하는 것과 같이 제가 시도한 접근 방식을 변경하는 것과는 다릅니다 .element-to-rotate.


1
나는 이것을 당분간 대답으로 받아 들였다. writing-modeIE 11이 지원 될 필요가없는 경우 솔루션은 가장 좋은 방법이 될 것입니다.
크리스

1
주목할만한 캐치 : 45deg와 같은 다른 회전에서는 작동하지 않습니다.
E. Villiger

받아 들여졌지만 이것은 최신 정답이 아닙니다. 쓰기 모드를 사용한 답변은 아래를 참조하십시오.
GilShalit

@ mark-amery, 내 코드의 CSS를 조정해야했습니다 : imgur.com/a/ZgafkgE 첫 번째 이미지를 CSS로, 두 번째 이미지를 조정하여 transformOrigin : 'top left'를 제거하고 transform : 'translate (-100 %)를 변경했습니다. ) ', to transform :'translate (20 %) ', <div style = {{flexDirection :'column ', alignItems :'center ',}}> <div style = {{display :'table ', margin : 30 ,}}> <div style = {{padding : '50 % 0 ', 높이 : 0}}> <img src = {image} style = {{display :'block ', marginTop :'-50 % ', transform : 'rotate (-90deg) translate (20 %)', maxWidth : 300, maxHeight : 400,}} /> </ div> </ div> <div> {title} </ div> </ div>
Dan 비터

44

으로 G-시르에 의해 댓글이 정당하게 지적, 현재 지원은 writing-mode괜찮은 이상입니다 . 간단한 회전과 결합하면 원하는 정확한 결과를 얻을 수 있습니다. 아래 예를 참조하십시오.

.statusColumn {
  position: relative;
  border: 1px solid #ccc;
  padding: 2px;
  margin: 2px;
  width: 200px;
}

.statusColumn i,
.statusColumn b,
.statusColumn em,
.statusColumn strong {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  white-space: nowrap;
  display: inline-block;
  overflow: visible;
}
<div class="container">
  <div class="statusColumn"><span>Normal</span></div>
  <div class="statusColumn"><a>Normal</a></div>
  <div class="statusColumn"><b>Rotated</b></div>
  <div class="statusColumn"><abbr>Normal</abbr></div>
</div>


1
스크롤을 내려서 기뻐요-이것은 회전과 번역을 사용하여 고통의 세계에서 저를 구했습니다.
James McLaughlin

3
사용 질문에 요청 회전을 얻으려면writing-mode: vertical-lr; transform: rotate(180deg);
제임스 맥 로린

41

불행히도 (?) 이것은 요소를 회전하더라도 여전히 일정한 너비와 높이를 가지며 회전 후에도 변경되지 않는 작동 방식이라고 가정합니다. 시각적으로 변경하지만 사물을 회전 할 때 크기가 변경되는 보이지 않는 포장 상자는 없습니다.

90 ° 미만으로 회전한다고 상상해보십시오 (예 :) transform: rotate(45deg): 회전하는 물체의 원래 치수와 실제 회전 값을 기반으로 한 모호한 치수를 가진 보이지 않는 상자를 도입해야합니다.

회전 된 개체

갑자기, 당신은 단지이없는 width그리고 height당신이 회전 한 개체의,하지만 당신은 또한이 width하고 height주변의 "보이지 않는 상자"의. 이 객체의 외부 너비를 요청한다고 상상해보세요. 무엇을 반환할까요? 개체의 너비 또는 새 상자? 둘을 어떻게 구별 할 수 있습니까?

따라서이 동작을 수정하기 위해 작성할 수있는 CSS가 없습니다 (또는 "자동화"라고 말해야 함). 물론 부모 컨테이너의 크기를 직접 늘리거나이를 처리하기 위해 JavaScript를 작성할 수 있습니다.

(명확하게 말하면을 사용하여 element.getBoundingClientRect이전에 언급 한 사각형을 얻을 수 있습니다 .)

으로 사양 설명 :

HTML 네임 스페이스에서 transform 속성은 변형 된 요소를 둘러싼 콘텐츠의 흐름에 영향을주지 않습니다.

즉, 손으로 변경하지 않는 한 변형중인 개체를 둘러싼 내용이 변경되지 않습니다.

객체를 변환 할 때 고려되는 유일한 것은 오버플로 영역입니다.

(...) 오버플로 영역의 범위는 변환 된 요소를 고려합니다. 이 동작은 요소가 상대 위치 지정을 통해 오프셋 될 때 발생하는 것과 유사합니다 .

자세한 내용은이 jsfiddle을 참조하십시오.

실제로 다음을 사용하여이 상황을 개체 오프셋과 비교하는 것이 좋습니다 position: relative.-개체를 이동하더라도 주변 콘텐츠가 변경되지 않습니다 ( ).


JavaScript를 사용하여이를 처리하려면 질문을 살펴보십시오 .


8
일반 UI 프레임 워크에서 부모의 너비와 높이는 자녀의 회전에 의해 언급 된대로 영향을받는 자녀의 경계 상자의 너비와 높이를 감싸 야한다고 말하고 싶습니다. 자식의 너비와 높이는 회전 전의 너비와 높이이며 부모의 너비와 높이는 자식의 bbox에 의해 정의됩니다. 그것은 매우 기본적이며 CSS / HTML이 그런 식으로 작동해야한다고 말하고 싶습니다 ...이 주제에 대해 아무도 질문을하지 않을 것입니다.이 주제는 해킹으로 만족스럽지 않은 방식으로 만 수정할 수 있습니다.
user18490

25

padding콘텐츠를 푸시 하려면 비율 및 의사 요소를 사용 합니다. JSFiddle에서는이를 표시하기 위해 의사 요소를 빨간색으로 남겨두고 텍스트 이동을 보정해야하지만 그게 갈 길이라고 생각합니다.

.statusColumn {
    position: relative;
    border: 1px solid #ccc;
    padding: 2px;
    margin: 2px;
    width: 200px;
}

.statusColumn i, .statusColumn b, .statusColumn em, .statusColumn strong {
  writing-mode: tb-rl;
  white-space: nowrap;
  display: inline-block;
  overflow: visible;
  -webkit-transform: rotate(-90deg);
  -moz-transform: rotate(-90deg);
  -ms-transform: rotate(-90deg);
  -o-transform: rotate(-90deg);
  transform: rotate(-90deg);
  -webkit-transform: rotate(-90deg);

  /* also accepts left, right, top, bottom coordinates; not required, but a good idea for styling */
  -webkit-transform-origin: 50% 50%;
  -moz-transform-origin: 50% 50%;
  -ms-transform-origin: 50% 50%;
  -o-transform-origin: 50% 50%;
  transform-origin: 50% 50%;

  /* Should be unset in IE9+ I think. */
  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
}
.statusColumn b:before{ content:''; padding:50% 0; display:block;  background:red; position:relative; top:20px
}
<div class="container">
    <div class="statusColumn"><span>Normal</span></div>
    <div class="statusColumn"><a>Normal</a></div>
    <div class="statusColumn"><b>Rotated</b></div>
    <div class="statusColumn"><abbr>Normal</abbr></div>
</div>

http://jsfiddle.net/MTyFP/7/

이 솔루션에 대한 글은 http://kizu.ru/en/fun/rotated-text/ 에서 찾을 수 있습니다.


3
이 해결책의 문제점은 요소가 있으므로 테이블 (예를 들어)에서, 원래의 폭 유지는 넓은 셀이라면, 불필요한 여백으로 폭이 열을 밀어내는 것 인 것이 텍스트 있었다면 용해 된 회전하지 않았습니다. 그거 짜증나네.
Jez

@litek, jsfiddle.net/MTyFP/7 좀 봐주 시겠어요 ? 이미지와 거의 동일한 문제가 있습니다. 질문 : stackoverflow.com/questions/31072959/…
Awlad Liton 2015-06-27

11

다른 답변 에서 업데이트 된 버전을 참조하십시오 . 이 답변은 더 이상 유효하지 않으며 더 이상 작동하지 않습니다. 나는 역사적인 이유로 여기에 두겠습니다.


이 질문은 꽤 오래지만, 현재 지원 .getBoundingClientRect()객체와 그 widthheight함께이 깔끔한 방법을 사용할 수있는 능력과 함께 값 transform, 내 솔루션에 언급되어야한다고 생각합니다.

여기 에서 실제로 확인 하십시오 . (Chrome 42, FF 33 및 37에서 테스트되었습니다.)

getBoundingClientRect요소 의 실제 상자 너비와 높이를 계산합니다 . 간단히 말해서 모든 요소를 ​​반복하고 최소 높이를 자식의 실제 상자 높이로 설정할 수 있습니다.

$(".statusColumn").each(function() {
    var $this = $(this),
        child = $this.children(":first");
    $this.css("minHeight", function() {
        return child[0].getBoundingClientRect().height;
    });
});

(일부 수정을 통해 하위 항목을 반복하여 어떤 것이 가장 큰지 알아 내고 부모의 키를 가장 큰 자녀로 설정할 수 있습니다. 그러나 예제를 더 간단하게 만들기로 결정했습니다. 또한 부모의 패딩을 추가 할 수 있습니다. 원하는 경우 높이 또는 box-sizingCSS에서 관련 값을 사용할 수 있습니다 .)

참고하지만, 그게 내가 추가 translate하고 transform-origin당신의 CSS에이 위치는보다 유연하고 정확하게 할 수 있습니다.

transform: rotate(-90deg) translateX(-100%);
transform-origin: top left;

정말? JQUERY 답변이 포함 된 CSS 질문이며 @MichaelLumbroso의 완벽한 답변이라고 부릅니다. 그것은 작동하지만 자바 스크립트 또는 jQuery와 같은 전체 js 라이브러리가 필요하지 않습니다
Nebulosar

1
@Nebulosar 좋은 파기. 당시 (이미 2 년 반 전!) 이것은 위치 지정이나 의사 요소가 제대로 작동하지 않는 문제를 일으키지 않는 유일한 대답이었습니다. 다행히도 일부 속성에 대한 브라우저 지원이 개선되었습니다. 내 편집을 참조하십시오.
Bram Vanroy

2
이것은 본질적으로 완전히 관련되지 않은 두 개의 답변입니다. 하나의 질문에 여러 답변을 게시하는 것은 완벽하게 규칙 내에 있습니다. 2017 년에 추가 된 새로운 솔루션이 새로운 답변 이었 더라면 두 개의 완전히 분리 된 답변을 따로 투표하고 댓글을 달 수 있었으면 좋았을 것 같습니다.
Mark Amery

@ MarkAmery 당신이 맞아요. 질문을 편집하고 여기에 새 답변을 추가했습니다 .
Bram Vanroy

이 답변과 이미지로드 이벤트를 사용하여 $ pic.on ( 'load', function () {$ pic.css ( 'min-height', $ pic [0]) 이미지에 대한 작업 솔루션을 얻을 수있었습니다. .getBoundingClientRect (). height);});
Miika L.

-18

나는 그것이 오래된 게시물이라는 것을 알고 있지만 똑같은 문제로 고투하면서 그것을 발견했습니다. 나를 위해 작동하는 솔루션은 단순히 90deg로 회전하는 div를 둘러싼 다소 조잡한 "낮은 기술"방법입니다.

<br>

div의 대략적인 너비 (회전 후 높이가 됨)를 알면이 div 주위에 br을 추가하여 차이를 보정 할 수 있으므로 그에 따라 위와 아래의 콘텐츠가 푸시됩니다.


10
아마도 이것은 효과가 있지만 절대 이렇게해서는 안됩니다.
MMM

의견을 보내 주셔서 감사합니다! 예, div의 margin-top 속성을 사용하여 개체가 회전 할 때 높이를 픽셀 단위로 조정하는 더 좋은 방법입니다.
vic_sk 2014-08-12
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.