CSS: Breite / Höhe als Prozentsatz minus Pixel einstellen


479

Ich versuche, einige wiederverwendbare CSS-Klassen für mehr Konsistenz und weniger Unordnung auf meiner Website zu erstellen, und ich versuche nicht, eine Sache zu standardisieren, die ich häufig verwende.

Ich habe einen Container <div>, für den ich die Höhe nicht festlegen möchte (da er je nach Standort auf der Site unterschiedlich ist). Darin befindet sich eine Kopfzeile <div>und dann eine ungeordnete Liste von Elementen, auf die CSS angewendet wird Sie.

Es sieht sehr ähnlich aus:

Widget

Ich mag , dass die ungeordnete Liste den verbleibenden Raum in dem Behälter nehmen <div>, wohl wissend , dass der Header <div>ist 18pxgroß. Ich weiß nur nicht, wie ich die Höhe der Liste als "Ergebnis von 100%Minus 18px" angeben soll .

Ich habe diese Frage in einigen anderen Kontexten zu SO gesehen, aber ich dachte, es lohnt sich, sie für meinen speziellen Fall erneut zu stellen. Hat jemand einen Rat in dieser Situation?


6
Einen Rand setzen? __
Kennytm

@KennyTM, ich nehme an, Sie schlagen vor, dass ich einen Rand oben auf meine ungeordnete Liste von beispielsweise 17px setze. Dies drückt jedoch nur die gesamte Liste nach unten. es schrumpft nicht, um im Behälter zu bleiben. Im Wesentlichen wird die aktuelle Höhe beibehalten, aber nur um 17 Pixel nach unten gedrückt. Dies löst mein Problem nicht, aber ich denke, es ist ein Schritt in die richtige Richtung, da ich online andere Ansätze gesehen habe, die diese Technik verwendet haben.
MegaMatt

Ich habe dieses Problem gerade in meiner Frage gelöst, die ich hier gepostet habe. stackoverflow.com/a/10420387/340947
Steven Lu

Antworten:


895

Mir ist klar, dass dies ein alter Beitrag ist, aber da er nicht vorgeschlagen wurde, ist es erwähnenswert, dass Sie Folgendes verwenden können, wenn Sie für CSS3-kompatible Browser schreiben calc:

height: calc(100% - 18px);

Es ist zu beachten, dass derzeit nicht alle Browser die Standardfunktion CSS3 calc () unterstützen. Daher kann die Implementierung der browserspezifischen Versionen der Funktion wie folgt erforderlich sein:

/* Firefox */
height: -moz-calc(100% - 18px);
/* WebKit */
height: -webkit-calc(100% - 18px);
/* Opera */
height: -o-calc(100% - 18px);
/* Standard */
height: calc(100% - 18px);

5
Ja, das ist vorerst normal.
Levi Botelho

1
Funktioniert für mich in IE10 und Chrome 27. Sie, Sir, sind mein verdammter Held!
BrainSlugs83

3
@ LeviBotelho Mein schlechtes. Hatte keinen Platz um den Bediener.
Benutzer

20
Auch wenn Sie Less verwenden, sollten Sie eine Datei mit kompilieren lessc --strict-math=on, um den Ausdruck innerhalb von calc- nur ein Problem, mit dem ich konfrontiert war und das ich viel Zeit verbrachte (ab Less 2.0.0)
Dmitry Wojciechowski

34
Beachten Sie, dass die Räume um das Minuszeichen sind nicht optional: 100%-18px, 100%- 18pxund 100% -18pxging nicht in den Browsern ich getestet.
Nisetama

71

Für einen etwas anderen Ansatz könnten Sie so etwas in der Liste verwenden:

position: absolute;
top: 18px;
bottom: 0px;
width: 100%;

Dies funktioniert so lange wie der übergeordnete Container position: relative;


1
Danke, Mann. Das Elterncontainer-Wesen position: relative;stolperte über mich.
gthmb

Für diejenigen, die sich vielleicht wie ich wundern: Position muss absoluteim Kindercontainer sein, kann es nicht sein relative.
Greg

Fortsetzung (Entschuldigung): Der Elternteil muss jedoch nur positioniert werden (dies kann auch der Fall absolutesein) und muss ebenfalls auf 100% Höhe eingestellt werden.
Greg

1
Leider funktioniert es nicht auf Safari iOS 8. (Getestet OK auf Android 4.1 Stock Browser und Standard FF 34) :-(
Greg

Dies kann in einigen Fällen funktionieren, kann aber auch zu Problemen führen, da absolut positionierte Elemente aus dem normalen Fluss entfernt werden (siehe stackoverflow.com/a/12821537/4173303) .
Christophe Weis

26

Ich benutze dafür Jquery

function setSizes() {
   var containerHeight = $("#listContainer").height();
   $("#myList").height(containerHeight - 18);
}

dann binde ich die Fenstergröße, um sie neu zu berechnen, wenn die Größe des Browserfensters geändert wird (wenn sich die Größe des Containers mit der Größe des Fensters ändert)

$(window).resize(function() { setSizes(); });

12
@puffpio, sicherlich ist JS eine Möglichkeit, dies von Fall zu Fall zu erreichen. Aber wie gesagt, ich versuche, das CSS generisch zu machen, damit es auf mehrere Seiten angewendet wird (die übrigens von einer Masterseite erben). Ich würde es also vorziehen, JS nicht zu verwenden. Aber danke für die Antwort.
MegaMatt

7
Fügen Sie Ihren Stil nicht in JavaScript ein.
Greg

8
@greg, nun, es wäre hilfreich, wenn CSS weitere nützliche Funktionen hätte. Einige Dinge, für die man Hacks machen muss, sind lächerlich.
Jonathan.

1
@puffpio Gute Lösung in der Tat. Aber verbindliche Ereignisse am Fenster sind für mich keine gute Lösung. Wenn meine Seite 3-4 oder mehr solcher Elemente enthält, muss ich die Höhe und Breite jedes Elements im Fenstergrößenänderungs-Handler aktualisieren. Dies wäre etwas langsamer als die CSS-Lösung.
sachinjain024

1
"Setzen Sie Ihr xyz nicht in JavaScript ein" bedeutet, "80% des Browsermarktes nicht unterstützen".
Beejor

16

Definieren Sie die Höhe nicht als Prozent, sondern stellen Sie einfach das top=0und bottom=0wie folgt ein:

#div {
   top: 0; bottom: 0;
   position: absolute;
   width: 100%;
}

Können Sie erklären, warum Sie die Höhe nicht auf ein Prozent einstellen?
Shrikant Sharat

@ShrikantSharat Dies ist Teil der visuellen Formatierungsspezifikation für absolut positionierte Elemente. Diese Lösung nutzt die Möglichkeit 5. "'Höhe' ist 'Auto', 'Oben' und 'Unten' sind nicht 'Auto', dann werden 'Auto'-Werte für' Rand oben 'und' Rand unten 'festgelegt auf 0 und lösen für 'Höhe' ". Der Browser kann die Höhe des Elements berechnen, da er weiß, wie weit es vom oberen und unteren Rand des übergeordneten Elements entfernt sein muss.
Ross Allen

Dies scheint zumindest in Firefox nicht zu funktionieren. Auch wenn alle übergeordneten Elemente auf height:100%und eingestellt sind display:block. Sonst wäre es eine sehr elegante Lösung. Interessanterweise margin:autokann ein Objekt mit fester Breite auch nicht vertikal zentriert werden, obwohl es horizontal einwandfrei funktioniert.
Beejor

8

Vorausgesetzte 17px-Headerhöhe

Liste CSS:

height: 100%;
padding-top: 17px;

Header CSS:

height: 17px;
float: left;
width: 100%;

Ja, das war es, worauf ich hinaus wollte.
dclowd9901

1
Das hat nicht ganz so gut funktioniert, wie ich gehofft hatte. Meine ungeordnete Liste wird unter diesem Header-Div gestartet. Das Header-Div nimmt Platz im Container ein. Wenn Sie also 17px auf die Liste setzen, wird es nur um 17px nach unten verschoben, wo es sich bereits im obigen Bild befindet, und nicht um 17px vom oberen Rand des Container-Div. Hier ist ein Bild von dem, was ich mit dem CSS in der obigen Antwort bekomme : i41.tinypic.com/mcuk1x.jpg . Ich schätze die Mühe jedoch und wenn Sie glauben, dass mir etwas fehlt, lassen Sie es mich bitte wissen. Übrigens habe ich Überlauf: Auto auch auf der ungeordneten Liste.
MegaMatt

2
Es wäre viel einfacher, dies zu beheben, wenn Sie das tatsächliche CSS veröffentlichen, damit wir genau sehen können, welche Interaktionen stattfinden. Eine andere Sache, die Sie versuchen könnten, ist der negative obere Rand Ihrer Ul. ul { margin-top: -17px; }
Ghoppe

7
  1. Verwenden Sie negative Ränder für das Element, für das Sie Pixel abziehen möchten. (gewünschtes Element)
  2. Machen Sie overflow:hidden;auf dem enthaltenden Element
  3. Schalten Sie overflow:auto;das gewünschte Element ein.

Es hat bei mir funktioniert!


3
Das hat mir sehr gut gefallen (ich musste nicht einmal den Überlauf ändern). Tolle Lösung, danke!
Aaj

1
Total genial! Ich habe es genossen, etwas über die beliebte "CSS calc" -Lösung zu lernen, aber dies ist viel einfacher und bietet eine breitere Browserunterstützung. Negative Ränder perfekt!
Simon Steinberger

Dies ist eine sehr elegante und kompatible Lösung. Der Hauptnachteil ist, dass das Element eine feste Höhe haben muss. Andernfalls müssten Sie JS verwenden oder calc()zur Laufzeit zentrieren. In vielen Fällen sollte dies jedoch kein Problem sein. Beachten Sie außerdem, dass die Verwendung vieler negativer Werte für Ränder, Auffüllungen und Offsets beim späteren Debuggen von Code zu Verwirrung führen kann. Versuchen Sie daher, die Dinge einfach zu halten.
Beejor

5

Versuchen Sie es mit Box-Sizing. Für die Liste:

height: 100%;
/* Presuming 10px header height */
padding-top: 10px;
/* Firefox */
-moz-box-sizing: border-box;
/* WebKit */
-webkit-box-sizing: border-box;
/* Standard */
box-sizing: border-box;

Für den Header:

position: absolute;
left: 0;
top: 0;
height: 10px;

Natürlich sollte der übergeordnete Container Folgendes haben:

position: relative;

3

Ein anderer Weg, um das gleiche Ziel zu erreichen: Flexboxen . Machen Sie den Container zu einer Spaltenflexbox, und Sie haben dann die Freiheit, einigen Elementen eine feste Größe (Standardverhalten) zu erlauben oder den Containerraum aufzufüllen / zu verkleinern (mit flex-grow: 1 und flex-). schrumpfen: 1).

#wrap {        
  display:flex;
  flex-direction:column;
}
.extendOrShrink {
  flex-shrink:1;
  flex-grow:1;
  overflow:auto;
}

Siehe https://jsfiddle.net/2Lmodwxk/ (versuchen Sie, das Fenster zu erweitern oder zu verkleinern, um den Effekt zu bemerken).

Hinweis: Sie können auch die Shorthand-Eigenschaft verwenden:

   flex:1 1 auto;

Ich glaube, dies ist heute die beste Antwort, da es bedeutet, keine festgelegte Höhe für das Header-Div (von 18 Pixel in meiner ursprünglichen Frage) angeben zu müssen und Dinge wie Auffüllen und Rand nicht subtrahieren zu müssen. Keine festgelegten Pixel, und alles kümmert sich um sich selbst.
MegaMatt

2

Ich habe einige der anderen Antworten ausprobiert, und keine davon hat so funktioniert, wie ich es wollte. Unsere Situation war sehr ähnlich, als wir einen Fensterkopf hatten und die Größe des Fensters mit Bildern im Fensterkörper geändert werden konnte. Wir wollten das Seitenverhältnis der Größenänderung sperren, ohne Berechnungen hinzufügen zu müssen, um die feste Größe des Headers zu berücksichtigen, und das Bild sollte dennoch den Fensterkörper füllen.

Unten habe ich ein sehr einfaches Snippet erstellt, das zeigt, was wir letztendlich gemacht haben. Es scheint für unsere Situation gut zu funktionieren und sollte mit den meisten Browsern kompatibel sein.

Bei unserem Fensterelement haben wir einen 20-Pixel-Rand hinzugefügt, der zur Positionierung relativ zu anderen Elementen auf dem Bildschirm beiträgt, aber nicht zur "Größe" des Fensters beiträgt. Die Fensterüberschrift wird dann absolut positioniert (wodurch sie aus dem Fluss anderer Elemente entfernt wird, sodass andere Elemente wie die ungeordnete Liste nicht verschoben werden), und ihre Oberseite wird mit -20 Pixel positioniert, wodurch die Überschrift innerhalb des Randes platziert wird des Fensters. Schließlich wird unser ul-Element zum Fenster hinzugefügt, und die Höhe kann auf 100% eingestellt werden, wodurch es den Körper des Fensters ausfüllt (ohne den Rand).

*,*:before,*:after
{
  box-sizing: border-box;
}

.window
{
  position: relative;
  top: 20px;
  left: 50px;
  margin-top: 20px;
  width: 150px;
  height: 150px;
}

.window-header
{
  position: absolute;
  top: -20px;
  height: 20px;
  border: 2px solid black;
  width: 100%;
}

ul
{
  border: 5px dashed gray;
  height: 100%;
}
<div class="window">
  <div class="window-header">Hey this is a header</div>
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
    <li>Item 5</li>
  </ul>
</div>


1

Danke, ich habe meine mit Ihrer Hilfe gelöst und ein wenig optimiert, da ich eine Div 100% Breite 100% Höhe (weniger Höhe einer unteren Leiste) und keine Schriftrolle am Körper (ohne Hack / Verstecken von Schriftrollen) möchte.

Für CSS:

 html{
  width:100%;height:100%;margin:0px;border:0px;padding:0px;
 }
 body{
  position:relative;width:100%;height:100%;margin:0px;border:0px;padding:0px;
 }
 div.adjusted{
  position:absolute;width:auto;height:auto;left:0px;right:0px;top:0px;bottom:36px;margin:0px;border:0px;padding:0px;
 }
 div.the_bottom_bar{
  width:100%;height:31px;margin:0px;border:0px;padding:0px;
}

Für HTML:

<body>
<div class="adjusted">
 // My elements that go on dynamic size area
 <div class="the_bottom_bar">
  // My elements that goes on bottom bar (fixed heigh of 31 pixels)
 </div>  
</div>  

Das hat den Trick gemacht, oh ja, ich habe einen etwas größeren Wert auf div gesetzt. Angepasst für den unteren als für die untere Balkenhöhe, sonst erscheint die vertikale Bildlaufleiste, ich habe den nächstgelegenen Wert angepasst.

Dieser Unterschied liegt darin, dass eines der Elemente im dynamischen Bereich ein zusätzliches unteres Loch hinzufügt, das ich nicht entfernen kann ... es ist ein Video-Tag (HTML5). Bitte beachten Sie, dass ich dieses Video-Tag mit diesem CSS ( Es gibt also keinen Grund dafür, ein unteres Loch zu machen, aber es tut es):

 video{
  width:100%;height:100%;margin:0px;border:0px;padding:0px;
 }

Das Ziel: Haben Sie ein Video, das 100% des Browers einnimmt (und die Größe dynamisch ändert, wenn die Größe des Browsers geändert wird, ohne das Seitenverhältnis zu ändern), abzüglich eines unteren Bereichs, den ich für ein Div mit einigen Texten, Schaltflächen usw. (und Validatoren) verwende w3c & css natürlich).

EDIT: Ich habe den Grund gefunden, Video-Tag ist wie Text, kein Blockelement, also habe ich es mit diesem CSS behoben:

 video{
  display:block;width:100%;height:100%;margin:0px;border:0px;padding:0px;
 }

Beachten Sie das display:block;Video-Tag.


0

Ich bin nicht sicher, ob dies in Ihrer speziellen Situation funktioniert, aber ich habe festgestellt, dass das Auffüllen des inneren Divs den Inhalt innerhalb eines Divs herumschiebt, wenn das enthaltende Div eine feste Größe hat. Sie müssten entweder schweben oder Ihr Header-Element absolut positionieren, aber ansonsten habe ich dies nicht für Divs mit variabler Größe versucht.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.