web-dev-qa-db-ja.com

親の高さに正しく影響するCSSの回転要素

いくつかの列があり、そのうちのいくつかを次の値に変更したいとします。

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%;
}

最終的には次のようになります。

A series of four block-level elements. The third element's text is rotated.

テキストが他の要素と重ならないように、回転した要素がその親の高さに影響するようなCSSを書くことは可能ですか?このようなもの:

The third column's text now affects its parent box's height such that the text fits within the box.

98
Chris

90度回転させたいと仮定すると、これはテキスト以外の要素でも可能です-しかし、CSSの多くの興味深いものと同様に、少し巧妙なことが必要です。私のソリューションはまた、CSS 2仕様に従って未定義の動作を技術的に呼び出します。したがって、Chrome、Firefox、Safari、およびEdgeで動作することをテストおよび確認しましたが、将来的に壊れないことはお約束できませんブラウザのリリース。

簡潔な答え

.element-to-rotate...を回転させるこのようなHTMLを指定します.

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

...回転させたい要素の周りにtwoラッパー要素を導入します:

<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;
}

スタックスニペットデモ

p {
  /* Tweak the visuals of the paragraphs for easier visualiation: */
  background: pink;
  margin: 1px 0;
  border: 1px solid black;
}
.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;
}
<div id="container">
  <p>Some text</p>
  <p>More text</p>
  <div class="rotation-wrapper-outer">
    <div class="rotation-wrapper-inner">
      <p class="element-to-rotate">Some rotated text</p>
    </div>    
  </div>
  <p>Even more text</p>
  <img src="https://i.stack.imgur.com/ih8Fj.png">
  <div class="rotation-wrapper-outer">
    <div class="rotation-wrapper-inner">
      <img class="element-to-rotate" src="https://i.stack.imgur.com/ih8Fj.png">
    </div>
  </div>
  <img src="https://i.stack.imgur.com/ih8Fj.png">
</div>

これはどのように作動しますか?

上記で使用した呪文に対する混乱は合理的です。多くのことが行われていますが、全体的な戦略は簡単ではなく、CSSトリビアの知識が必要です。順を追って説明しましょう。

私たちが直面する問題の核心は、 transform CSSプロパティを使用して要素に適用される変換はすべて、レイアウトが行われた後に発生することです。つまり、要素でtransformを使用しても、その親または他の要素のサイズや位置にはまったく影響しません。 transformの動作方法に関するこの事実を変更する方法はまったくありません。したがって、要素を回転させ、その親の高さを回転に合わせる効果を作成するには、次のことを行う必要があります。

  1. 何らかの方法で、高さが.element-to-rotateの幅と等しいother要素を構築します
  2. ステップ1の要素に正確にオーバーレイするように、変換を.element-to-rotateに記述します。

ステップ1の要素は.rotation-wrapper-outerでなければなりません。しかし、どのようにしてそのheight.element-to-rotatewidthと等しくすることができますか?

ここでの戦略の重要なコンポーネントは、padding: 50% 0上の.rotation-wrapper-innerです。このエクスプロイトの paddingの仕様のエキセントリックな詳細padding-topおよびpadding-bottomであっても、その割合のパディングは常にの割合として定義されます要素のコンテナの幅。これにより、次の2段階のトリックを実行できます。

  1. display: table.rotation-wrapper-outerを設定します。これにより、 shrink-to-fit width になります。これは、コンテンツの固有の幅に基づいて、つまり.element-to-rotateの固有の幅に基づいて幅が設定されることを意味します。 。 (サポートしているブラウザーでは、width: max-contentでこれをよりきれいに達成できますが、2017年12月の時点で、max-contentEdgeではまだサポートされていません です。)
  2. .rotation-wrapper-innerheightを0に設定し、そのパディングを50% 0に設定します(つまり、上部50%、下部50%)。これにより、親の幅の100%に等しい垂直方向のスペースが使用されます。これは、ステップ1のトリックにより、.element-to-rotateの幅に等しくなります。

次に、子要素の実際の回転と配置を実行するだけです。当然、transform: rotate(-90deg)は回転を行います。 transform-Origin: top left;を使用して、回転した要素の左上隅の周りで回転を発生させます。これにより、回転した要素が描画された場所のすぐ上に残るため、後続の翻訳の推論が容易になります。次に、translate(-100%)を使用して、要素を回転前の幅に等しい距離だけ下にドラッグします。

.rotation-wrapper-outerの50%の上部パディングのためにまだオフセットする必要があるため、それでもまだ正しい位置を取得できません。 .element-to-rotatedisplay: blockがあることを確認して(マージンが適切に機能するように)、-50%margin-topを適用します-マージンの割合はalso親要素の幅に対して定義されます。

以上です!

なぜこれが完全に仕様に準拠していないのですか?

仕様のパディングとマージンの割合の定義からの次の注意 (ボルディング鉱山):

パーセンテージは、生成されたボックスの 包含ブロックwidthに関して計算されます- 'padding-top' および 'padding-bottom'包含ブロックの幅がこの要素に依存する場合、結果のレイアウトはCSS 2.1で定義されません。

全体のトリックは、内側のラッパー要素のパディングをその子の幅に依存するコンテナの幅に相対的にすることを中心に展開されているため、この条件に達し、未定義の動作を呼び出しています。現時点では、4つの主要なブラウザーすべてで動作します-.rotation-wrapper-innerを親ではなく.element-to-rotateの兄弟に変更するなど、仕様に準拠しているように見える一部の調整方法とは異なります。

37
Mark Amery

残念ながら(?)これは、要素を回転させたとしても、一定の幅と高さを持ちながらも、回転後も変わらないということです。視覚的に変更しますが、物を回転させるとサイズが変更される非表示のラッピングボックスはありません。

90°未満で回転することを想像してください(例:transform: rotate(45deg)):回転しているオブジェクトの元の寸法と実際の回転値に基づいてあいまいな寸法を持つ、このような不可視のボックスを導入する必要があります。

Rotated object

突然、回転したオブジェクトのwidthheightだけでなく、その周りの「見えないボックス」のwidthheightもあります。 。このオブジェクトの外側の幅を要求することを想像してください-それは何を返しますか?オブジェクトの幅、または新しいボックス?両方をどのように区別しますか?

したがって、この動作を修正するために記述できる(または「自動化」する必要がある)CSSはありません。もちろん、親コンテナのサイズを手動で増やすことも、JavaScriptを記述してそれを処理することもできます。

(明確にするために、 element.getBoundingClientRect を使用して、前述の四角形を取得してみてください)。

仕様に記載

HTML名前空間では、transformプロパティは、変換された要素を囲むコンテンツのフローに影響しません。

これは、手動で変更しない限り、変換しているオブジェクトの周囲のコンテンツに変更が加えられないことを意味します。

オブジェクトを変換するときに考慮される唯一のものは、オーバーフロー領域です。

(...)オーバーフロー領域の範囲は、変換された要素を考慮します。この動作はに似ていますが、要素が相対位置調整によってオフセットされるとどうなりますか

詳細については、このjsfiddleを参照してください。

position: relative-オブジェクトを動かしても、周囲のコンテンツは変化しません( example )。


JavaScriptを使用してこれを処理する場合は、 this の質問をご覧ください。

40
MMM

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/

25
Litek

G-Cyrのコメント が正しく指摘しているように、 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>
21
Bram Vanroy

my other answer の更新バージョンをご覧ください。この答えはもはや有効ではなく、もはや機能しません。歴史的な理由でここに置いておきます。


この質問はかなり古いですが、 .getBoundingClientRect() オブジェクトとそのwidthおよびheight値の現在のサポートにより、このきちんとしたメソッドをtransformと一緒に使用する機能と組み合わせて、私の解決策について言及する必要があると思います同じように。

実際にご覧ください here 。 (Chrome 42、FF 33および37でテスト済み。)

getBoundingClientRectは、要素の実際のbox幅と高さを計算します。簡単に言えば、すべての要素をループし、そのmin-heightを子の実際のボックスの高さに設定できます。

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

(いくつかの変更を行うと、子をループして、最も高い子を見つけて、親の高さを最も高い子に設定できます。しかし、この例はより簡単にすることにしました。必要に応じて高さ、またはCSSで関連するbox-sizing値を使用できます。

ただし、CSSにtranslatetransform-Originを追加して、位置決めをより柔軟かつ正確にすることに注意してください。

transform: rotate(-90deg) translateX(-100%);
transform-Origin: top left;
10
Bram Vanroy

書き込みモードプロパティがこれを行います。 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>

Bram Vanroy による回答から分割)

3
Simon Gibbs