Czy możesz zrobić ten układ HTML bez używania tabel?

102

Ok, tydzień lub dwa temu miałem prosty problem z układem. Mianowicie sekcje strony wymagały nagłówka:

+---------------------------------------------------------+
| Title                                            Button |
+---------------------------------------------------------+

Całkiem proste rzeczy. Rzecz w tym, że nienawiść do tabel zdaje się przejąć kontrolę w świecie sieci Web, o czym przypomniałem sobie, gdy zapytałem Po co używać tagów list definicji (DL, DD, DT) w formularzach HTML zamiast tabel? Teraz omówiono już ogólny temat tabel vs div / CSS, na przykład:

Więc to nie jest ogólna dyskusja na temat CSS i tabel w układzie. To jest po prostu rozwiązanie jednego problemu. Wypróbowałem różne rozwiązania powyższego za pomocą CSS, w tym:

  • Przenieś się w prawo dla przycisku lub elementu div zawierającego przycisk;
  • Pozycja względem przycisku; i
  • Pozycja względna + bezwzględna.

Żadne z tych rozwiązań nie było zadowalające z różnych powodów. Na przykład względne pozycjonowanie spowodowało problem z indeksem Z, w którym moje menu rozwijane pojawiło się pod treścią.

Więc wróciłem do:

<style type="text/css">
.group-header { background-color: yellow; width: 100%; }
.group-header td { padding: 8px; }
.group-title { text-align: left; font-weight: bold; }
.group-buttons { text-align: right; }
</style>
<table class="group-header">
<tr>
  <td class="group-title">Title</td>
  <td class="group-buttons"><input type="button" name="Button"></td>
</tr>
</table>

I działa doskonale. Jest to proste, tak kompatybilne wstecz, jak to tylko możliwe (prawdopodobnie będzie działać nawet w IE5) i po prostu działa. Bez majstrowania przy pozycjonowaniu lub pływaniu.

Czy więc każdy może zrobić odpowiednik bez tabel?

Wymagania są następujące:

  • Kompatybilny wstecz: do FF2 i IE6;
  • Raczej spójne: w różnych przeglądarkach;
  • Wyśrodkowany w pionie: przycisk i tytuł mają różną wysokość; i
  • Elastyczny: umożliwia dość precyzyjną kontrolę nad pozycjonowaniem (wyściółką i / lub marginesem) i stylizacją.

Na marginesie, trafiłem dzisiaj na kilka interesujących artykułów:

EDYCJA: Pozwól mi rozwinąć kwestię pływaka. Tego rodzaju prace:

<html>
  <head>
    <title>Layout</title>
    <style type="text/css">
      .group-header, .group-content { width: 500px; margin: 0 auto; }
      .group-header { border: 1px solid red; background: yellow; overflow: hidden; }
      .group-content { border: 1px solid black; background: #DDD; }
      .group-title { float: left; padding: 8px; }
      .group-buttons { float: right; padding: 8px; }
    </style>
  </head>
  <body>
    <div class="group-header">
      <div class="group-title">This is my title</div>
      <div class="group-buttons"><input type="button" value="Collapse"></div>
    </div>
    <div class="group-content">
      <p>And it works perfectly. It's simple, as backward compatibile as it gets (that'll work probably even on IE5) and it just works. No messing about with positioning or floats.</p>
      <p>So can anyone do the equivalent without tables that is backwards compatible to at least FF2 and IE6?</p>
      <p>On a side note, I came across a couple of interesting articles today:</p>
    </div>
  </body>
</html>

Dzięki Ant P za tę overflow: hiddenczęść (nadal nie rozumiem dlaczego). Tutaj pojawia się problem. Powiedzmy, że chcę, aby tytuł i przycisk były wyśrodkowane w pionie. Jest to problematyczne, ponieważ elementy mają różną wysokość. Porównaj to z:

<html>
  <head>
    <title>Layout</title>
    <style type="text/css">
      .group-header, .group-content { width: 500px; margin: 0 auto; }
      .group-header { border: 1px solid red; background: yellow; overflow: hidden; }
      .group-content { border: 1px solid black; background: #DDD; }
      .group-header td { vertical-align: middle; }
      .group-title { padding: 8px; }
      .group-buttons { text-align: right; }
    </style>
  </head>
  <body>
    <table class="group-header">
    <tr>
      <td class="group-title">This is my title</td>
      <td class="group-buttons"><input type="button" value="Collapse"></td>
    </tr>
    </table>
    <div class="group-content">
      <p>And it works perfectly. It's simple, as backward compatibile as it gets (that'll work probably even on IE5) and it just works. No messing about with positioning or floats.</p>
      <p>So can anyone do the equivalent without tables that is backwards compatible to at least FF2 and IE6?</p>
      <p>On a side note, I came across a couple of interesting articles today:</p>
    </div>
  </body>
</html>

który działa doskonale.

cletus
źródło
11
Ok, to ma sens "Jakiego koloru powinienem użyć do vima?" zostanie pozytywnie rozpatrzony, mój problem z układem CSS zostaje odrzucony.
cletus
w każdym przypadku możesz robić, co chcesz, bez stołu. Również dlaczego, do diabła, @SamB wpadło na to 2-letnie pytanie? DOH +
dynamiczny
3
@ yes123: cóż, podświetlanie składni było złe ...
SamB

Odpowiedzi:

50

Nie ma nic złego w korzystaniu z dostępnych narzędzi do szybkiego i prawidłowego wykonania pracy.

W tym przypadku stół działał idealnie.

Osobiście użyłbym do tego stołu.

Uważam, że należy unikać zagnieżdżonych tabel, może się to pogmatwać.

Gregor Brandt
źródło
21
Z wyjątkiem sytuacji, gdy używasz tabeli do układu prezentacji, a nie danych tabelarycznych, tylko dlatego, że na początku jest łatwiejsza, w takim przypadku podążasz ciemną i niebezpieczną ścieżką.
Jedna kredka
9
Nawet Amazon używa tabel w niektórych przypadkach. A także stackoverflow.com. Jestem zwolennikiem rozwiązań CSS, które faktycznie działają dobrze.
Nosredna
11
Ani amazon, teraz stackoverflow to szczyty projektowania stron internetowych.
Bobby Jack
31
Może nie, ale to działające rozwiązania, które obsługują dziesiątki tysięcy użytkowników.
17 z 26
22
Ten antystołowy mem jest po prostu stary, głupi. Jedynym dwuwymiarowym menedżerem układu dla elastycznych rozwiązań opartych na wiązaniach jest tabela; i to, czy jest to tylko jeden skomplikowany (z niezliczoną liczbą kolumn / rozpiętości wierszy), czy zagnieżdżone, nie ma większego znaczenia. Ale wydaje się, że rzeczywistość i fakty nie zawsze są wystarczająco dobrą bronią przeciwko zeloterii.
StaxMan
28

Po prostu płyń w lewo i w prawo i ustaw, aby wyczyścić oba i gotowe. Nie ma potrzeby stołów.

Edycja: Wiem, że otrzymałem za to wiele głosów za i wierzyłem, że miałem rację. Ale są przypadki, w których po prostu potrzebujesz tabel. Możesz spróbować zrobić wszystko z CSS i będzie działać w nowoczesnych przeglądarkach, ale jeśli chcesz wspierać starsze ... Nie powtarzam się, tutaj powiązany wątek przepełnienia stosu i rant na moim blogu .

Edit2: Ponieważ starsze przeglądarki nie są już tak interesujące, używam ładowania początkowego Twittera do nowych projektów. Jest świetny dla większości potrzeb związanych z układem i korzysta z CSS.

Milan Babuškov
źródło
2
Nie radzi sobie z centrowaniem w pionie, więc -1.
SamB
1
Miałem podobny problem, gdy miałem logo po lewej stronie i niektóre menu tekstowe po prawej. Menu musiały być wyrównane do linii bazowej logo. Używanie float: prawo do menu nie działa. Przesyła je do prawego górnego rogu i nie były już wyrównane pionowo z linią bazową logo.
Jean-François Beauchamp,
1
Myślę, że wyśrodkowanie w pionie można rozwiązać, ustawiając wysokość wiersza tytułu na taką samą, jak wysokość przycisku.
igors
1
@igors, +1, masz rację. Pamiętajcie, że to pytanie pochodzi z 2009r.;)
Milan Babuškov 22.11.13
17

To trochę podchwytliwe pytanie: wygląda strasznie prosto, dopóki tego nie zrobisz

Powiedzmy, że chcę, aby tytuł i przycisk były wyśrodkowane w pionie.

Chcę na wstępie stwierdzić, że tak, centrowanie w pionie jest trudne w CSS. Kiedy ludzie publikują posty i wydaje się to nieskończone w SO, „czy możesz zrobić X w CSS”, odpowiedź prawie zawsze brzmi „tak”, a ich narzekanie wydaje się nieuzasadnione. W tym przypadku tak, ta jedna rzecz jest trudna.

Ktoś powinien po prostu zredagować całe pytanie do „czy wyśrodkowanie w pionie jest problematyczne w CSS?”.

AmbroseChapel
źródło
11
To trochę mój problem z argumentem „nienawidzących tabel”: CSS może zrobić wszystko, co tabele ... z wyjątkiem kilku całkiem prostych, powszechnych i rozsądnych przypadków (takich jak wyśrodkowanie w pionie). CSS po prostu wygląda na zepsutą obietnicę wyborczą.
cletus
4
Chodziło mi o to, że centrowanie w pionie jest właściwie JEDYNĄ rzeczą, która jest naprawdę trudna.
AmbroseChapel
3
CSS nie zastępuje tabel; ma to po prostu umożliwić rozwiązanie większości typowych problemów z układem bez tabel. Jeśli stół działa, użyj stołu, tak jakbyś używał pióra do rysowania zamiast młotka kowalskiego.
Aaron Digulla
16

Ruchomy tytuł w lewo, ruchomy przycisk w prawo i (oto część, której nie znałem do niedawna) - utwórz pojemnik z nich obu {overflow:hidden}.

W każdym razie powinno to uniknąć problemu z indeksem Z. Jeśli to nie działa, a naprawdę potrzebujesz obsługi IE5, skorzystaj z tabeli.


źródło
+1 Whoa, o co chodzi z ukrytym przepełnieniem? To robi różnicę. Nie mam pojęcia, dlaczego.
cletus
Szczerze mówiąc, ja też tego nie rozumiem i nie mogłem znaleźć żadnej wzmianki o tym w specyfikacji. Ktoś powiedział mi jednak, że to „właściwy” sposób, po tym jak odpowiedziałem na inne pytanie, sugerując, że używa do tego wyczyszczonego elementu. Wydaje mi się, że to dobry pomysł.
Elementy pływające nadal muszą zostać wyczyszczone, aby następująca po nich zawartość przepływała prawidłowo. przepełnienie: ukryte; dotyczy tylko wysokości kontenera.
Zack The Human
2
„overflow: hidden” to sposób na osiągnięcie ZARÓWNO „rozszerzania się” wysokości, jak i czyszczenia. Następujące elementy BĘDĄ wyczyścić to pole (przynajmniej w przeglądarkach, które poprawnie implementują tę część specyfikacji).
Bobby Jack
1
-1 dla braku obsługi wyśrodkowania w pionie, ale +2 dla overflow:hidden.
SamB
7

W czystym CSS, działającą odpowiedzią będzie pewnego dnia po prostu użycie "display:table-cell". Niestety, nie działa to w obecnych przeglądarkach klasy A, więc równie dobrze możesz użyć tabeli, jeśli i tak chcesz osiągnąć ten sam wynik. Przynajmniej będziesz mieć pewność, że działa to wystarczająco daleko w przeszłość.

Szczerze mówiąc, po prostu użyj stołu, jeśli jest to łatwiejsze. To nie będzie bolało.

Jeśli semantyka i dostępność elementu tabeli naprawdę mają dla Ciebie znaczenie, istnieje robocza wersja robocza, aby uczynić tabelę niesemantyczną:

http://www.w3.org/TR/wai-aria/#presentation

Myślę, że to wymaga specjalnego poza DTD XHTML 1.1, który będzie po prostu wmieszać się w cały text/htmlvs application/xmldebaty, więc niech nie tam.

A więc do twojego nierozwiązanego problemu CSS ...

Aby wyrównać w pionie dwa elementy na ich środku: można to zrobić na kilka różnych sposobów, z pewnym zawiłym hakerem CSS.

Jeśli możesz zmieścić się w następujących ograniczeniach, istnieje stosunkowo prosty sposób:

  • Wysokość obu elementów jest stała.
  • Wysokość pojemnika jest stała.
  • Elementy będą wystarczająco wąskie, aby się nie nakładały (lub można je ustawić na stałą szerokość).

Następnie możesz użyć pozycjonowania bezwzględnego z ujemnymi marginesami:

.group-header { height: 50px; position: relative; }
.group-title, .group-buttons { position: absolute; top: 50%; }
# Assuming the height of .group-title is a known 34px
.group-title { left: 0; margin-top: -17px; }
# Assuming the height of .group-buttons is a known 38px
.group-buttons { right: 0; margin-top: -19px; }

Ale to nie ma sensu w większości sytuacji ... Jeśli znasz już wysokość elementów, możesz po prostu użyć pływaków i dodać wystarczający margines, aby ustawić je w razie potrzeby.

Oto kolejna metoda, która wykorzystuje linię bazową tekstu do wyrównania w pionie dwóch kolumn jako bloków wbudowanych. Wadą jest to, że musisz ustawić stałe szerokości kolumn, aby wypełnić szerokość od lewej krawędzi. Ponieważ musimy trzymać elementy zablokowane na linii bazowej tekstu, nie możemy po prostu użyć float: right dla drugiej kolumny. (Zamiast tego musimy zrobić pierwszą kolumnę na tyle szeroką, aby ją przesunąć.)

<html>
  <head>
    <title>Layout</title>
    <style type="text/css">
      .group-header, .group-content { width: 500px; margin: 0 auto; }
      .group-header { border: 1px solid red; background: yellow; }
      .valign { display: inline-block; vertical-align: middle; }
      .group-content { border: 1px solid black; background: #DDD; }
      .group-title { padding: 8px; width: 384px; }
      .group-buttons { padding: 8px; width: 84px; text-align: right; }
    </style>
    <!--[if lt IE 8]>
    <style type="text/css">
      .valign { display: inline; margin-top: -2px; padding-top: 1px; }
    </style>
    <![endif]-->
  </head>
  <body>
    <div class="group-header">
      <div class="valign">
        <div class="group-title">This is my title.</div>
      </div><!-- avoid whitespace between these! --><div class="valign">
        <div class="group-buttons"><input type="button" value="Collapse"></div>
      </div>
    </div>
    <div class="group-content">
      <p>And it works perfectly, but mind the hacks.</p>
    </div>
  </body>
</html>

HTML: dodajemy otoki .valign wokół każdej kolumny. (Nadaj im bardziej „semantyczną” nazwę, jeśli to cię uszczęśliwi.) Te muszą być zachowane bez spacji pomiędzy nimi, bo inaczej spacje tekstowe rozsuwają je od siebie. (Wiem, że to jest do bani, ale to właśnie otrzymujesz, będąc „czystym” ze znacznikami i oddzielając je od warstwy prezentacji ... Ha!)

CSS: używamy vertical-align:middledo wyrównania bloków do linii bazowej tekstu elementu nagłówka grupy. Różne wysokości każdego bloku pozostaną wyśrodkowane w pionie i wypchną wysokość ich pojemnika. Szerokości elementów należy obliczyć tak, aby pasowały do ​​szerokości. Tutaj są 400 i 100, bez poziomego wypełnienia.

Poprawki IE: Internet Explorer wyświetla blok inline tylko dla elementów natywnie wbudowanych (np. Span, a nie div). Ale jeśli podamy element div hasLayout, a następnie wyświetlimy go w tekście, będzie on zachowywał się tak samo, jak inline-block. Regulacja marginesów polega na naprawieniu 1 piks. Przerwy u góry (spróbuj dodać kolory tła do tytułu .group, aby zobaczyć).

Andrew Vit
źródło
1
Hmm, wyświetlacz: tagi table-X wydają się mieć cel do tworzenia układu przy użyciu tabel, tylko bez używania tagów tabeli?
Żeglarz naddunajski
3

W tym przypadku nie zalecałbym używania tabeli, ponieważ nie są to dane tabelaryczne; umieszczenie przycisku po prawej stronie ma charakter czysto prezentacyjny. Oto, co zrobiłbym, aby zduplikować strukturę tabeli (zmień na inny H #, aby dopasować się do miejsca w hierarchii witryny):

<style>
  .group-header { background: yellow; zoom: 1; padding: 8px; }
  .group-header:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
  /* set width appropriately to allow room for button */
  .group-header h3 { float: left; width: 300px; }
  /* set line-height or margins to align with h3 baseline or middle */
  .group-header input { float: right; }
</style>

<div class="group-header">
  <h3>This is my title</h3>
  <input type="button" value="Collapse"/>
</div>

Jeśli chcesz, aby prawdziwe wyrównanie w pionie znajdowało się na środku (tj. Jeśli tekst zawija się, przycisk jest nadal wyrównany do środka w stosunku do obu wierszy tekstu), musisz albo zrobić tabelę, albo coś z position: absolutemarginesami i zrobić . Możesz dodać position: relativedo swojego menu rozwijanego (lub, co bardziej prawdopodobne, jego element nadrzędny), aby przyciągnąć go do tego samego poziomu kolejności co przyciski, umożliwiając podbijanie go nad nimi za pomocą indeksu z, jeśli o to chodzi.

Zauważ, że nie potrzebujesz width: 100%na div, ponieważ jest to element blokowy i zoom: 1sprawia, że ​​div zachowuje się tak, jakby miał poprawkę clearfix w IE (inne przeglądarki wybierają rzeczywisty clearfix). Nie potrzebujesz również wszystkich tych dodatkowych klas, jeśli celujesz w rzeczy bardziej szczegółowo, chociaż możesz potrzebować opakowującego elementu div lub rozpiętości na przycisku, aby ułatwić pozycjonowanie.

Jedna kredka
źródło
Twoje rozwiązanie nie działa jednak na IE6 z powodu pseudoklasy: after.
Sebastian Hoitz,
1
Działa w IE 6, dzięki zoom: 1in .group-header, który wyzwala hasLayout i powoduje, że IE 6 zachowuje się tak samo, jakby miał aktywny element: after.
One Crayon
2

Zrób podwójny float w div i użyj clearfix. http://www.webtoolkit.info/css-clearfix.html Czy masz jakieś ograniczenia dotyczące dopełnienia / marginesów?

<div class="clearfix">
   <div style="float:left">Title</div>
   <input type="button" value="Button" style="float:right" />
</div>
Bendewey
źródło
Mam wymóg wyśrodkowania w pionie (i trochę dodatkowej wyściółki). Myślę, że wyjaśniłem to po tym, jak opublikowałeś.
cletus
2
<div class="group-header">
    <input type="button" name="Button" value="Button" style="float:right" />
    <span>Title</span>
</div>
Omer Bokhari
źródło
1

Zdecydowałem się na Flexbox, ponieważ to znacznie ułatwiło sprawę.

Zasadniczo musisz udać się do rodzica dzieci, które chcesz wyrównać i dodać display:box(oczywiście z prefiksem). Aby umieścić je po bokach, użyj justify-content . Przestrzeń między jest właściwą rzeczą, gdy masz elementy, które muszą być wyrównane do końca, tak jak w tym przypadku (patrz link) ...

Następnie kwestia wyrównania w pionie. Ponieważ uczyniłem rodzicem dwóch elementów, chcesz wyrównać Flexbox. Teraz jest łatwy w użyciu align-items: center.

Następnie dodałem style, które chciałeś wcześniej, usunąłem pływak z tytułu i przycisku w nagłówku i dodałem wypełnienie:

.group-header, .group-content {
    width: 500px;
    margin: 0 auto;
}
.group-header{
    border: 1px solid red;
    background: yellow;
    overflow: hidden;
    display: -webkit-box;
    display: -moz-box;
    display: box;
    display: -webkit-flex;
    display: -moz-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-justify-content: space-between;
    -moz-justify-content: space-between;
    -ms-justify-content: space-between;
    -o-justify-content: space-between;
    justify-content: space-between;
    webkit-align-items: center;
    -moz-align-items: center;
    -ms-align-items: center;
    -o-align-items: center;
    align-items: center;
    padding: 8px 0;
}
.group-content{
    border: 1px solid black;
    background: #DDD;
}
.group-title {
    padding-left: 8px;
}
.group-buttons {
    padding-right: 8px
}

Zobacz Demo

user3522940
źródło
1

Zgadzam się, że naprawdę należy używać tabel tylko do danych tabelarycznych, z tego prostego powodu, że tabele nie są wyświetlane, dopóki nie zostaną zakończone ładowanie (bez względu na to, jak szybkie to jest; jest wolniejsze niż metoda CSS). Uważam jednak, że jest to najprostsze i najbardziej eleganckie rozwiązanie:

<html>
    <head>
        <title>stack header</title>
        <style type="text/css">
            #stackheader {
                background-color: #666;
                color: #FFF;
                width: 410px;
                height: 50px;
            }
            #title {
                color: #FFF;
                float: left;
                padding: 15px 0 0 15px;
            }
            #button {
                color: #FFF;
                float: right;
                padding: 15px 15px 0 0;
            }
        </style>
    </head>

    <body>
        <div id="stackheader">
        <div id="title">Title</div>
        <div id="button">Button</div>
        </div>
    </body>
</html>

Funkcja przycisku i wszelkie dodatkowe szczegóły mogą być stylizowane z tej podstawowej formy. Przepraszamy za złe tagi.

Galen777
źródło