Rotated <table> column headers wurde bereits hier auf CSS-Tricks behandelt, also ein Dankeschön dafür, dass es mir den Einstieg erleichtert und mir geholfen hat, diesen Effekt zu erzielen. Wie im Artikel erwähnt, müssen Sie, wenn Sie keine Trigonometrie zur Berechnung Ihrer Tabellenstile verwenden, auf magische Zahlen zurückgreifen, und Ihre Tabelle wird spröde sein und alle Träume von Responsivität zerschlagen.
Glücklicherweise können wir in diesem Fall die Trigonometrie entfernen und durch sorgfältige Geometrie ersetzen, und all unsere magischen Zahlen werden zu 0 (einer wirklich magischen Zahl).
Für diejenigen, die es eilig haben, hier ist das CSS (es ist dem Stil im anderen Artikel sehr ähnlich). Unten finden Sie eine ausführliche Erläuterung.
<th class="rotate"><div><span>Column Header 1</span></div></th>
table {
border-collapse: collapse;
--table-border-width: 1px;
}
th.rotate {
white-space: nowrap;
position: relative;
}
th.rotate > div {
/* place div at bottom left of the th parent */
position: absolute;
bottom: 0;
left: 0;
/* Make sure short labels still meet the corner of the parent otherwise you'll get a gap */
text-align: left;
/* Move the top left corner of the span's bottom-border to line up with the top left corner of the td's border-right border so that the border corners are matched
* Rotate 315 (-45) degrees about matched border corners */
transform:
translate(calc(100% - var(--table-border-width) / 2), var(--table-border-width))
rotate(315deg);
transform-origin: 0% calc(100% - var(--table-border-width));
width: 100%;
}
th.rotate > div > span {
/* make sure the bottom of the span is matched up with the bottom of the parent div */
position: absolute;
bottom: 0;
left: 0;
border-bottom: var(--table-border-width) solid gray;
}
td {
border-right: var(--table-border-width) solid gray;
/* make sure this is at least as wide as sqrt(2) * height of the tallest letter in your font or the headers will overlap each other*/
min-width: 30px;
padding-top: 2px;
padding-left: 5px;
text-align: right;
}
Lassen Sie uns diese Tabelle aufschlüsseln und sehen, was vor sich geht. Der Zauber beginnt mit dieser merkwürdigen Kette von HTML-Tags. Wir platzieren einen <span> innerhalb eines <div> innerhalb unseres <th>. Ist das alles wirklich notwendig? Zwischen dem Verhalten von Rändern, der benötigten Flexibilität bei der Positionierung und dem, was die Breite einer Tabellenspalte bestimmt ... ja, jeder hat seinen Zweck und ist notwendig.
Mal sehen, was passiert, wenn wir die <th> direkt drehen
<th class="rotate">Column header 1</th>
table {
border-collapse: collapse;
}
th.rotate {
border-bottom: 1px solid gray;
transform: rotate(315deg);
white-space: nowrap;
}
td {
border-right: 1px solid gray;
min-width: 30px;
padding-top: 2px;
padding-left: 5px;
text-align: right;
}

Wenn wir die Tatsache ignorieren, dass wir die Position nicht korrigiert haben, gibt es hier zwei große Probleme:
- Die Spaltenbreite wird immer noch aus der Länge der Kopfzeile berechnet, was wir vermeiden wollten.
- Unser Rand kam nicht mit uns in die Drehung, weil er tatsächlich Teil der Tabelle ist.
Diese Probleme sind nicht so schwer zu beheben. Wir wissen, dass der Browser, wenn die <th> ein Kindelement mit einem Rand hat, diesen Rand nicht als Teil der Tabelle behandelt. Weiterhin wissen wir, dass absolut positionierte Elemente aus dem Dokumentfluss genommen werden und die Breite des übergeordneten Elements nicht beeinflussen. Betreten Sie das <div> Tag, links auf der Bühne... und rechts, denke ich.
<th class="rotate"><div>Column header 1</div></th>
table {
border-collapse: collapse;
}
th.rotate {
white-space: nowrap;
position: relative;
}
th.rotate > div {
position: absolute;
transform: rotate(315deg);
border-bottom: 1px solid gray;
}
td {
border-right: 1px solid gray;
min-width: 30px;
text-align: right;
padding-top: 2px;
padding-left: 5px;
}

Im Bild mit den gedrehten <th> Elementen ist es einfacher zu erkennen, aber diese Drehung erfolgt um die Mitte des Elements (das ist das Standardverhalten von transform-origin). Es ist nur eine weitere Transformation in x und y, um es an die richtige Stelle zu bringen, aber hier müssten wir Trigonometrie verwenden, um herauszufinden, wie viel x und y benötigt werden, um es mit den Spaltenrändern auszurichten. Wenn wir stattdessen sorgfältig den Punkt wählen, um den die Kopfzeile gedreht werden soll, und transform-origin verwenden, um ihn auszuwählen, können wir zu Distanzen gelangen, die einfacher als magische Zahlen sind.
Die Animation unten hilft zu veranschaulichen, was wir tun werden, um komplizierte Mathematik zu vermeiden. Der schwarze Punkt in der oberen linken Ecke des blauen Rands muss mit dem roten Punkt am rechten Rand der Tabellenspalte übereinstimmen und sich um diesen drehen. Dann wird es keine Lücken zwischen den beiden Rändern geben.
Es ist nicht hilfreich, irgendwohin zu gehen, wenn man nicht weiß, wo man ist. Die absolute Positionierung wird uns dabei helfen. Durch die Angabe von bottom: 0; left: 0; auf dem <div> landet es unten links in der übergeordneten <th>. Das bedeutet, dass die untere linke Ecke des <div>-Randes auf dem linken Spaltenrand liegt und auf halbem Weg durch diesen hindurchgeht. Von hier aus ist ersichtlich, dass wir uns um eine Randbreite nach unten und um eine Zellenbreite nach rechts bewegen müssen, aber wie bekommen wir das responsiv hin? Genau in diesem Moment erinnern Sie sich vielleicht, dass wir den <span> noch nicht hinzugefügt haben - wir werden ihn brauchen!
Wir verwenden das <div>, um "herauszufinden", wie groß die Tabellenzellen sind, und den <span>, um den Text tatsächlich zu halten und ihn absolut zu positionieren, damit er die übergeordnete Komponente überlappt.
<th class="rotate"><div><span>Column header 1</span></div></th>
th.rotate{
white-space: nowrap;
position: relative;
}
th.rotate > div {
position: absolute;
bottom: 0;
left: 0;
width: 100%; /* <- now the div parent is as wide as the columns */
}
th.rotate > div > span {
position: absolute;
bottom: 0;
left: 0;
border-bottom: 1px solid gray;
}
Großartig! Wenn wir die Breite des <div> auf 100% setzen, enthält es die Informationen über die Größe der Spalte, unabhängig vom Inhalt der Tabellenzellen. Mit diesem eingerichtet können wir die Dinge einfach um die Breite des <div> verschieben - aber vergessen Sie nicht, dass wir eine halbe Randbreite abziehen müssen. Unsere Verschiebung wird
transform: translate( calc( 100% - var(--table-border-width)/2), var(--table-border-width));
Das <div> befindet sich nun an der richtigen Stelle zum Drehen, aber wir müssen sicherstellen, dass wir die richtige transform-origin wählen. Wir wollen, dass sie sich an der oberen linken Ecke des Randes befindet, die sich links und eine Randbreite über der Unterseite unseres <div> Elements befindet.
transform-origin: 0%, calc(100% - var(--table-border-width));
Das bringt uns zu unserem endgültigen Stil für die Tabellenkopfzeile.
table {
border-collapse: collapse;
--table-border-width: 1px;
}
th.rotate{
white-space: nowrap;
position: relative;
}
th.rotate > div {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
transform:
translate( calc( 100% - var(--table-border-width)/2), var(--table-border-width));
rotate(315deg);
transform-origin: 0%, calc(100% - var(--table-border-width));
}
th.rotate > div > span {
position: absolute;
bottom: 0;
left: 0;
border-bottom: var(--table-border-width) solid gray;
}
Beachten Sie, dass Transformationen nach der Platzierung aller Elemente stattfinden. Das bedeutet, dass die gedrehten Kopfzeilen so gut wie möglich über alles andere überlappen werden. Sie müssen die gesamte Tabelle in etwas einpacken, um die unerwartete Höhe auszugleichen. Ich habe den Titel und die Tabelle in ein Flexbox <div> zusammengefasst und die flex-basis des Titels auf einen Wert gesetzt, der groß genug ist, um die hohen Kopfzeilen auszugleichen.
#div-with-table {
display: flex;
flex-direction: column;
justify-content: space-around;
}
#title {
flex-basis: 140px;
}
Interessanter und gründlicher Artikel, danke :)
Wenn der thead-Text nur vertikal (nicht schräg) sein soll, können Sie writing-mode effektiv einsetzen, ohne absolute Positionierung oder magische Zahlen (abgesehen von line-height:0).
(Diese Demo ist ein paar Jahre alt, könnte also verbessert werden.)
Dies wird fehlschlagen, wenn der thead-Text <b> oder <p> enthält.
Hier ist eine weitere Lösung ohne CSS, nur mit JavaScript.
https://github.com/napengam/vertical
Ah ja, ich liebe den Schreibmodus und wie er vertikale Spaltenüberschriften so einfach macht. Wenn es doch nur eine Kultur gäbe, die mit 45-Grad-schrägen Linien schreiben würde!
Das ist großartig! Danke für die großartige Referenz.
Ja, meine Demo war nur für eine einzelne Zeile gedacht. ;) Ich denke, wenn Sie mehrere Zeilen haben, sieht es sehr unübersichtlich aus, aber jeder wie er mag.
Ihre JS-Version sieht gut und nützlich aus :). Das einzige, was ich auszusetzen habe (abgesehen von der Verwendung von JS) ist, dass sie nicht text-zoom-fähig ist und der Inhalt überlappen wird (im Gegensatz zu meinem Beispiel). Die CSS-Tricks-Demo wird ebenfalls darunter leiden.
Hallo Paul
Könnten Sie bitte erklären, was Sie meinen mit...
„... es ist nicht text-zoom-fähig und der Inhalt wird überlappen...“
Grüße
Hallo Heinz,
Ich möchte diese Diskussion nicht vom ursprünglichen Thema ablenken (obwohl die Antwort auch für den Artikel relevant sein könnte), aber als Antwort auf Ihre Frage: Ich habe mein Firefox so eingestellt, dass es nur den Text zoomt, da ich es so einfacher lesen kann (anstatt das gesamte Layout zu zoomen). Wenn ich Ihre Demo vergrößere, wird der Text überlappen, da Sie den Text mit Ihrem JS in Container mit fester Höhe gesetzt haben. (Natürlich ist mir bewusst, dass Sie dies mit mehr JS und Zoom-Erkennung etc. berücksichtigen könnten.) :)
weniger Magie
Das bringt Sie fast ans Ziel! Ich habe überlegt, diesen Punkt zu diskutieren, aber weil Sie die Breite des
<div>auf 100 % gesetzt haben, bedeutet dies, dass Ihr Rand immer nur die Breite der Zellen haben wird. Wenn es nicht wichtig ist, dass Ihre gesamte Kopfzeile unterstrichen ist (oder in diesem Fall haben Sie gar keinen unteren Rand), dann ist dies sicherlich der richtige Weg, aber bedenken Sie, dass sie, wenn Sie einen unteren Rand hinzufügen/wünschen, unterschiedliche Längen haben werden, basierend auf dem Zellinhalt ohne den<span>.