親の高さに正しく影響する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つのブロックレベル要素のシリーズ。 3番目の要素のテキストが回転します。

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

3列目のテキストは、テキストがボックス内に収まるように、親ボックスの高さに影響します。


1
役に立つことができstackoverflow.com/questions/7565542/...
ピート・

7
書き込みモードは、ほとんどのブラウザーで使用可能になりました(IE5の機能になるために使用します)今日はjsfiddle.net/MTyFP/698を使用します。参照:developer.mozilla.org/en-US/docs/Web/CSS/writing-mode
G-キリルス

1
@ G-Cyr writing-modeはほとんどのブラウザで利用できますが、ひどくバグがあります。関連する質問について、私はあきらめる前にブラウザー固有のバグを回避しようと何度も繰り返しました。stackoverflow.com/posts/47857248/revisionsで私の一連の失敗を確認できます。ここでは、FirefoxやEdgeでは機能せず、Chromeで機能するものから始め、その後、他の2つを修正する過程でChromeを中断し、最終的に回答し、Chrome専用としてラベルを付けます。この道を進みたければ、用心してください。(また、それが非テキスト要素
Mark Amery

1
afaik writing-modeはテキストでのみ機能します...
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>

... 回転する要素の周りに2つのラッパー要素を導入します。

<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-rotateステップ1の要素に正確にオーバーレイするなどの変換を記述します。

手順1の要素はです.rotation-wrapper-outer。しかし、どのようにしてその高さ.element-to-rotateと等しくすることができますか?

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

  1. 私たちは、セットdisplay: table.rotation-wrapper-outer。これにより、合わせ縮小されます。つまり、その幅は、コンテンツの固有の幅に基づいて、つまりの固有の幅に基づいて設定され.element-to-rotateます。(サポートしているブラウザーでは、を使用してこれをより明確に実現できますが、width: max-content2017年12月の時点でmax-contentは、まだEdgeではサポートされていません。)
  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-rotate持っているdisplay: block(そうマージンがそれに正常に動作すること)し、その後-50%適用margin-top割合のマージンがあることに注意してください- また、親要素の幅に関連して定義します。

以上です!

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

仕様(太字の鉱山)におけるパーセンテージのパディングとマージンの定義からの次の注記のため:

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

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


1
今のところ、これを答えとして受け入れました。writing-modeIE 11をサポートする必要がない場合の解決策は、最善のアプローチとなります。
Chris

1
注目すべき点:45度などの他の回転では機能しません。
E.ヴィリガー2018

受け入れられましたが、これは最新の正解ではありません。書き込みモードを使用した回答については、以下を参照してください。
GilShalit

@ mark-amery、私はコードに合わせてCSSを調整する必要がありました:imgur.com/a/ZgafkgE最初の画像をCSSで、2番目の画像を調整して、transformOrigin: '左上'を削除し、変換を変更: 'translate(-100% ) '、変換:' translate(20%) '、<div style = {{flexDirection:' column '、alignItems:' center '、}}> <div style = {{display:' table '、margin:30 、}}> <div style = {{padding:'50%0 '、height:0}}> <img src = {image} style = {{display:' block '、marginTop:' -50% '、transform : 'rotate(-90deg)translate(20%)'、maxWidth:300、maxHeight:400、}} /> </ div> </ div> <div> {title} </ div> </ div>
ダン苦い

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
スクロールダウンしてよかった-これにより、ローテーションと翻訳を使用して苦痛の世界から私を救いました。
ジェームズマクラフリン

3
質問で要求されるローテーションを取得するには、次を使用しますwriting-mode: vertical-lr; transform: rotate(180deg);
James McLaughlin

40

残念なことに(?)これは、要素を回転させても要素の幅と高さが一定であり、回転後も変化しない場合に機能すると想定されている方法です。視覚的に変更しますが、回転させるとサイズが変化する非表示のラッピングボックスはありません。

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

回転したオブジェクト

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

したがって、この動作を修正するために作成できる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

11

私の他の答えで更新されたバージョンを参照してください。この回答は無効になり、単に機能しなくなります。歴史的な理由でここに置いておきます。


この質問はかなり古いですが、ために現在サポートして.getBoundingClientRect()オブジェクトとそのwidthheight一緒に、このきちんとした方法を使用する機能との組み合わせで値が、transform私は私の解決策が同様に言及されるべきだと思います。

こちらで実際の動作をご覧ください。(Chrome 42、FF 33および37でテスト済み。)

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

$(".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と呼んでいますか?動作しますが、JavaScriptやjQueryのようなjsライブラリ全体は必要ありません
Nebulosar

1
@Nebulosarニース掘り。当時(すでに2年半前です!)、これは、配置や疑似要素がうまく機能しない問題を引き起こさなかった唯一の回答でした。幸いなことに、いくつかのプロパティに対するブラウザのサポートが改善されました。私の編集を見てください。
Bram Vanroy 2017年

2
これは本質的に、完全に無関係な2つの答えを1つにまとめたものです。1つの質問に複数の回答を投稿することは完全にルール内です。2017年に追加された新しいソリューションが新しい回答であった場合、2つの完全に異なる回答に投票してコメントを個別に付けられるようにした方がよかったと思います。
Mark Amery

@MarkAmeryそうですね。質問を編集して、ここに新しい回答を追加しました。
Bram Vanroy、

私はこの回答と画像読み込みイベントを使用して、次の方法で画像の実用的なソリューションを取得できました:$ pic.on( 'load'、function(){$ pic.css( 'min-height'、$ pic [0] .getBoundingClientRect()。height);});
Miika L.

-18

私はそれが古い記事であることを知っていますが、まったく同じ問題に取り組んでいるときに見つけました。私にとって有効な解決策は、90度回転するdivを単に

<br>

divのおおよその幅(回転後に高さになります)がわかっているので、このdivの周りにbrを追加することで、上下のコンテンツがそれに応じてプッシュされるようにすることで、違いを補正できます。


10
多分これはうまくいくかもしれませんが、あなたはこれをするべきではありません。
MMM 2014

ご意見ありがとうございます!はい、オブジェクトを回転したときにdivのmargin-topプロパティを使用して高さをピクセル単位で調整するより良い方法です。
vic_sk 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.