CSS'de, ebeveynlerinin yüksekliğini doğru şekilde etkileyen döndürülmüş öğeler


119

Diyelim ki, bazılarının değerlerini döndürmek istediğim birkaç sütunum var:

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>

Bu CSS ile:

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

Şöyle görünüyor:

Bir dizi dört blok düzeyi öğe.  Üçüncü öğenin metni döndürülür.

Metnin diğer öğelerle çakışmaması için döndürülen öğenin üst öğesinin yüksekliğini etkilemesine neden olacak herhangi bir CSS yazmak mümkün müdür? Bunun gibi bir şey:

Üçüncü sütunun metni artık, metin kutuya sığacak şekilde üst kutusunun yüksekliğini etkiler.



7
yazma modu artık çoğu tarayıcı için kullanılabilir (bir IE5 özelliği olarak kullanın) Bugünlerde yapacağım jsfiddle.net/MTyFP/698 bkz: developer.mozilla.org/en-US/docs/Web/CSS/writing-mode
G-Cyrillus

1
G-Cyr @ writing-modeolan mevcut en tarayıcılar için, ama korkunç arabası. İlgili bir soru üzerinde, pes etmeden önce tarayıcıya özgü hataların üstesinden gelmeye çalışarak birçok kez denedim; Başarısızlıklarımı stackoverflow.com/posts/47857248/revisions adresinde görebilirsiniz , burada Chrome'da çalışan ancak Firefox veya Edge'de çalışmayan bir şeyle başlayıp, diğer ikisini düzeltme sürecinde Chrome'u kırıp sonunda yanıtlayın ve yalnızca Chrome olarak etiketleyin. Bu yoldan gitmek istiyorsanız dikkatli olun. (Metin olmayan öğelerle hiçbir faydası olmadığını da unutmayın.)
Mark Amery

1
afaik yazma modu yalnızca metin üzerinde çalışır ...
Fredrik Johansson

Yanıtlar:


51

90 derece döndürmek istediğinizi varsayarsak, bu, metin olmayan öğeler için bile mümkündür - ancak CSS'deki birçok ilginç şey gibi, biraz kurnazlık gerektirir. Çözümüm aynı zamanda teknik olarak CSS 2 spesifikasyonuna göre tanımlanmamış davranışa neden oluyor - bu yüzden Chrome, Firefox, Safari ve Edge'de çalıştığını test edip onaylarken, size gelecekte bozulmayacağına söz veremem tarayıcı sürümü.

Kısa cevap

Bunun gibi HTML verildiğinde, döndürmek istediğiniz yer .element-to-rotate...

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

... döndürmek istediğiniz öğenin etrafına iki sarmalayıcı öğe ekleyin:

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

... ve ardından saat yönünün tersine döndürmek için aşağıdaki CSS'yi kullanın (veya transformsaat yönünde dönüşe çevirmenin bir yolu için açıklamaya bakın ):

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

Yığın snippet demosu

Bu nasıl çalışıyor?

Yukarıda kullandığım büyülü sözler karşısında kafa karışıklığı makul; Devam eden çok şey var ve genel strateji basit değil ve anlamak için biraz CSS trivia bilgisi gerekiyor. Adım adım ilerleyelim.

Karşılaştığımız sorunun özü, transformCSS özelliğini kullanarak bir öğeye uygulanan dönüşümlerin hepsinin düzen gerçekleştikten sonra gerçekleşmesidir. Başka bir deyişle, transformbir öğede kullanmak , üst öğesinin veya diğer öğelerin boyutunu veya konumunu hiçbir şekilde etkilemez. Nasıl transformçalıştığına dair bu gerçeği değiştirmenin kesinlikle bir yolu yok . Bu nedenle, bir öğeyi döndürme etkisini yaratmak ve üst öğenin yüksekliğinin dönüşe uygun olmasını sağlamak için aşağıdakileri yapmamız gerekir:

  1. Her nasılsa , yüksekliği nesnenin genişliğine eşit olan başka bir öğe inşa edin..element-to-rotate
  2. Dönüşümümüzü, .element-to-rotatetam olarak 1. adımdaki öğenin üzerine gelecek şekilde yazın.

1. adımdaki öğe olacaktır .rotation-wrapper-outer. Ama nasıl biz onun neden olabilir yüksekliği eşit olacak şekilde .element-to-rotate'ın genişliği ?

Buradaki stratejimizin temel bileşeni padding: 50% 0açık .rotation-wrapper-inner. Bu istismar , spesifikasyonun eksantrik bir detayıdırpadding : bu yüzde dolgular, padding-topve için bile padding-bottom, her zaman öğenin kapsayıcısının genişliğinin yüzdeleri olarak tanımlanır . Bu, aşağıdaki iki adımlı numarayı gerçekleştirmemizi sağlar:

  1. Biz set display: tableüzerinde .rotation-wrapper-outer. Bu , sığdırmak için daralan genişliğe sahip olmasına neden olur ; bu, genişliğinin, içeriğinin iç genişliğine, yani iç genişliğine dayalı olarak ayarlanacağı anlamına gelir .element-to-rotate. (Tarayıcıları destekleyerek, biz daha temiz olan bu elde edebiliriz width: max-content, ancak Aralık 2017 tarihi itibariyle, max-contentolduğu hala Kenar desteklenmez .)
  2. Belirlenen heightbir .rotation-wrapper-innerdaha sonra için doldurma ayarlamak, 0 50% 0(olup,% 50 ve üst% 50 altında). Bu, üst öğesinin genişliğinin% 100'üne eşit dikey alanı kaplamasına neden olur - bu, 1. adımdaki hile ile genişliğine eşittir .element-to-rotate.

Daha sonra, geriye kalan tek şey, alt öğenin gerçek dönüşünü ve konumlandırmasını gerçekleştirmektir. Doğal olarak transform: rotate(-90deg)rotasyon yapar; transform-origin: top left;Döndürmenin, döndürülen öğenin sol üst köşesi etrafında gerçekleşmesine neden olmak için kullanırız , bu, döndürülen öğeyi, aksi takdirde çizileceği yerin hemen üzerinde bıraktığı için, sonraki çevirmenin mantıklı olmasını kolaylaştırır. Daha sonra kullanabiliriztranslate(-100%) , öğeyi dönüş öncesi genişliğine eşit bir mesafe kadar aşağı doğru sürüklemek için .

Bu hala konumlandırmayı tam olarak doğru yapmıyor, çünkü yine de% 50 üst dolgu için dengelememiz gerekiyor .rotation-wrapper-outer. Bunu, .element-to-rotatesahip display: blockolduğundan emin olarak (böylece kenar boşlukları üzerinde düzgün çalışacak) ve ardından margin-top- % 50 uygulayarak başarırız - yüzde kenar boşluklarının da ana öğenin genişliğine göre tanımlandığını unutmayın .

Ve bu kadar!

Bu neden tamamen spesifikasyonlara uygun değil?

Spesifikasyondaki yüzde dolguları ve marjların tanımındaki aşağıdaki not nedeniyle (kalın benim):

Yüzde, 'padding-top' ve 'padding-bottom' için bile , oluşturulan kutunun içeren bloğunun genişliğine göre hesaplanır . İçeren bloğun genişliği bu elemana bağlıysa, ortaya çıkan düzen CSS 2.1'de tanımsızdır.

Tüm hile, iç sarma elemanının dolgusunun, daha sonra çocuğun genişliğine bağlı olan kabının genişliğine göre olmasını sağlamak etrafında döndüğü için, bu koşula ulaşıyor ve tanımsız davranışı çağırıyoruz. Şu anda 4 ana tarayıcının hepsinde çalışıyor - denediğim yaklaşım .rotation-wrapper-inneriçin .element-to-rotate, bir ebeveyn yerine kardeş olmak gibi, görünüşte spesifikasyonlara uygun bazı ince ayarların aksine .


1
Şimdilik bunu cevap olarak kabul ettim. writing-modeIE 11 desteklenmeye ihtiyacı yoksa çözümleri en iyi yaklaşımı olacaktır.
Chris

1
Dikkate değer yakalama: 45deg gibi diğer rotasyonlar için çalışmaz.
E. Villiger

kabul edilmesine rağmen, bu güncel doğru cevap değildir. Yazma modunu kullanan cevaplar için aşağıya bakın.
GilShalit

@ mark-amery, benim kodum için CSS'yi ayarlamam gerekiyordu: imgur.com/a/ZgafkgE 1. görüntü CSS'nizle, ikincisi ayarlamalarla transformOrigin: 'üst sol' ve değiştirilmiş dönüşüm: 'çeviri (-% 100 ) ', dönüştürmek için:' 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% ', dönüşüm : 'rotate (-90deg) translate (20%)', maxWidth: 300, maxHeight: 400,}} /> </div> </div> <div> {title} </div> </div>
Dan Bitter

44

Gibi G-Cyr tarafından comment haklı işaret, şu anki destek writing-modenezih daha fazladır . Basit bir döndürme ile birleştirildiğinde, istediğiniz kesin sonucu elde edersiniz. Aşağıdaki örneğe bakın.

.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
Aşağı kaydırdığıma sevindim - bu beni rotasyonları ve çevirileri kullanarak acı dolu bir dünyadan kurtardı.
James McLaughlin

3
Soruda istenen rotasyonu elde etmek için şunu kullanınwriting-mode: vertical-lr; transform: rotate(180deg);
James McLaughlin 18

41

Ne yazık ki (?) Bu, öğenizi döndürseniz bile, belirli bir genişlik ve yüksekliğe sahip olmasına rağmen, dönüşten sonra değişmeyen bu şekilde çalışması varsayılır. Görsel olarak değiştirirsiniz, ancak nesneleri döndürdüğünüzde boyutunu değiştiren görünmez bir ambalaj kutusu yoktur.

90 ° 'den daha az döndürdüğünüzü hayal edin (örneğin transform: rotate(45deg)): döndürdüğünüz nesnenin orijinal boyutlarına ve gerçek döndürme değerine dayalı olarak artık belirsiz boyutlara sahip olan görünmez bir kutuyu tanıtmanız gerekir.

Döndürülmüş nesne

Aniden, sadece yok widthve heightnesnenin sen çevirmiş, ama aynı zamanda sahip widthveheight etrafında "görünmez kutu". Bu nesnenin dış genişliğini talep ettiğinizi hayal edin - ne döndürür? Nesnenin genişliği mi, yoksa yeni kutumuz mu? İkisini nasıl ayırt edeceğiz?

Bu nedenle, bu davranışı düzeltmek için yazabileceğiniz CSS yoktur (veya "otomatikleştirin" demeliyim). Elbette, üst kapsayıcınızın boyutunu elle artırabilir veya bunun üstesinden gelmek için biraz JavaScript yazabilirsiniz.

(Açık olmak gerekirse, element.getBoundingClientRectdaha önce bahsedilen dikdörtgeni elde etmek için kullanmayı deneyebilirsiniz ).

Spesifikasyonda açıklandığı gibi :

HTML ad alanında, dönüştürme özelliği, dönüştürülen öğeyi çevreleyen içeriğin akışını etkilemez.

Bu, dönüştürmekte olduğunuz nesneyi çevreleyen içerikte, elle yapmadığınız sürece hiçbir değişiklik yapılmayacağı anlamına gelir.

Nesnenizi dönüştürürken dikkate alınan tek şey taşma alanıdır:

(...) taşma alanının kapsamı dönüştürülmüş öğeleri hesaba katar. Bu davranış, elemanlar göreceli konumlandırma yoluyla kaydırıldığında olana benzer .

Daha fazlasını öğrenmek için bu jsfiddle'a bakın.

Aslında, bu durumu aşağıdakileri kullanarak bir nesne ofsetiyle karşılaştırmak oldukça iyidir: position: relative- nesnenizi hareket ettirseniz bile çevreleyen içerik değişmez ( örnek ).


Bunu JavaScript kullanarak halletmek istiyorsanız, bu soruya bir göz atın .


8
Normal bir UI çerçevesinde ebeveynlerinizin genişliğinin ve boyunun, çocuğun rotasyonlarından bahsettiğiniz gibi etkilenen çocuğun sınırlayıcı kutusunun genişliği ve yüksekliği etrafına sarılması gerektiğini söyleyebilirim. Çocukların genişliği ve yüksekliği, dönmeden önceki genişlik ve yüksekliğidir ve ebeveynlerin genişliği ve yüksekliği, çocukların bbox'ı tarafından belirlenir. Bu çok basit ve CSS / HTML'nin bu şekilde çalışması gerektiğini söyleyebilirim ... Eğer bu konu hakkında hiç kimse soru sormazdı, bu sadece hacks ile tatmin edici olmayan şekillerde düzeltilebilir.
user18490

25

paddingİçeriği iletmek için yüzdeler ve sözde öğe kullanın. JSFiddle'da sözde öğeyi göstermek için kırmızı bıraktım ve metnin kaymasını telafi etmeniz gerekecek, ancak bence bu gitmenin yolu.

.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/

Bu çözümün bir yazımı burada bulunabilir: http://kizu.ru/en/fun/rotated-text/


3
Bu çözüm ile sorun elemanı, yani bir tablo (örneğin) içinde, orijinal genişliğini tutar o en geniş hücre olsaydı, gereksiz boşluk ile geniş konusu sütunu dışarı itmek olduğunu ifade ediyorum metin olsaydı kadar alınmış döndürülmemiş. Bu rahatsız edici.
Jez

@litek, lütfen jsfiddle.net/MTyFP/7 adresine bir göz atabilir misiniz? Görüntü ile neredeyse aynı sorunu yaşıyorum. Soru: stackoverflow.com/questions/31072959/…
Awlad Liton

11

Lütfen diğer cevabımdaki güncellenmiş versiyona bakın . Bu cevap artık geçerli değil ve artık işe yaramıyor. Tarihi nedenlerden dolayı burada bırakacağım.


Bu soru oldukça eski, ama şu anki desteği ile .getBoundingClientRect()nesne ve onun widthve heightbirlikte bu düzgün yöntemi kullanma yeteneği ile birlikte değerlerin transform, benim çözüm de söz gerektiğini düşünüyorum.

Burada iş başında görün . (Chrome 42, FF 33 ve 37'de test edilmiştir.)

getBoundingClientRectöğenin gerçek kutu genişliğini ve yüksekliğini hesaplar . O halde oldukça basit bir şekilde, tüm öğeler arasında döngü yapabilir ve minimum yüksekliğini çocuklarının gerçek kutu yüksekliğine ayarlayabiliriz.

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

(Bazı değişikliklerle çocuklar arasında döngü oluşturabilir ve hangisinin en uzun olduğunu öğrenebilir ve ebeveynin boyunu en uzun çocuğa ayarlayabilirsiniz. Ancak, örneği daha açık hale getirmeye karar verdim. Ayrıca, ebeveynin dolgusunu da ekleyebilirsiniz. İsterseniz yükseklik veya box-sizingCSS'de ilgili bir değer kullanabilirsiniz .)

Yine de, konumlandırmayı daha esnek ve doğru hale getirmek için CSS'nize bir translateve ekledim transform-origin.

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

Gerçekten mi? JQUERY cevabı olan bir css sorusu ve siz buna mükemmel bir cevap mı diyorsunuz @MichaelLumbroso? Evet çalışıyor, ancak javascript veya jQuery gibi bütün bir js kitaplığına gerek yok
Nebulosar

1
@Nebulosar Güzel kazma. O zamanlar (zaten iki buçuk yıl önce!) Bu, konumlandırma veya sözde öğelerle ilgili herhangi bir soruna neden olmayan tek yanıttı. Neyse ki, bazı özellikler için tarayıcı desteği gelişti. Lütfen düzenlememe bakın.
Bram Vanroy

2
Bu, esasen birbiriyle tamamen alakasız iki cevaptır. Bir soruya birden fazla yanıt göndermek tamamen kurallara dahildir; Bence 2017'de eklenen yeni çözümünüz yeni bir cevap olsaydı, tamamen ayrı iki cevabın ayrı ayrı oylanıp yorumlanabilmesi için tercih edilirdi.
Mark Amery

@MarkAmery Haklısın. Soruyu düzenledim ve buraya yeni bir cevap ekledim .
Bram Vanroy

$ Pic.on ('load', function () {$ pic.css ('min-height', $ pic [0] kullanarak görüntüler için çalışan bir çözüm elde etmek için bu yanıtı ve görüntü yükleme olayını kullanabildim .getBoundingClientRect (). yükseklik);});
Miika L.

-18

Eski bir gönderi olduğunu biliyorum ama tam olarak aynı sorunla uğraşırken buldum. Benim için işe yarayan çözüm, 90 derece döndürdüğüm div'i çok sayıda

<br>

Div I'in yaklaşık genişliğini (dönüşten sonra yükseklik haline gelir) bilmek, bu div'in etrafına br'leri ekleyerek farkı telafi edebilir, böylece yukarı ve aşağı içerik buna göre itilir.


10
Belki bu işe yarar ama bunu asla yapmamalısın.
MMM

Geri bildiriminiz için teşekkürler! Evet, nesne döndürüldüğünde yüksekliği piksel cinsinden ayarlamak için div'in margin-top özelliğini kullanmanın daha iyi bir yolu.
vic_sk
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.