CSS: impostazione larghezza / altezza come percentuale meno pixel


479

Sto cercando di creare alcune classi CSS riutilizzabili per maggiore coerenza e meno confusione sul mio sito, e sono bloccato nel tentativo di standardizzare una cosa che uso frequentemente.

Ho un contenitore per il <div>quale non voglio impostare l'altezza (perché varierà a seconda di dove si trova il sito), e al suo interno c'è un'intestazione <div>, quindi un elenco non ordinato di elementi, tutti con CSS applicato a loro.

Sembra molto simile a questo:

Aggeggio

Voglio che l' elenco non ordinato occupi la stanza rimanente nel contenitore <div>, sapendo che l'intestazione <div>è 18pxalta. Semplicemente non so come specificare l'altezza della lista come "il risultato di 100%meno 18px".

Ho visto questa domanda posta in un paio di altri contesti su SO, ma ho pensato che varrebbe la pena chiedere di nuovo il mio caso particolare. Qualcuno ha qualche consiglio in questa situazione?


6
Impostare un margine? __
kennytm,

@KennyTM, presumo tu stia suggerendo di mettere un margine in cima al mio elenco non ordinato, diciamo, 17px. Ma questo spinge l'intera lista verso il basso; non fa sì che si restringa nel contenitore. Fondamentalmente, la sua altezza attuale viene mantenuta, ma è solo ridotta di 17px. Questo non risolve il mio problema, ma penso che sia un passo nella giusta direzione perché ho visto altri approcci online che hanno usato questa tecnica.
MegaMatt

Ho appena risolto questo problema nella mia domanda che ho pubblicato qui. stackoverflow.com/a/10420387/340947
Steven Lu

Risposte:


895

Mi rendo conto che questo è un vecchio post, ma dato che non è stato suggerito vale la pena ricordare che se stai scrivendo per browser compatibili con CSS3, puoi usare calc:

height: calc(100% - 18px);

Vale la pena notare che al momento non tutti i browser supportano la funzione calc () CSS3 standard, quindi potrebbe essere necessario implementare versioni specifiche della funzione del browser come il seguente:

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

5
Sì, per il momento è normale.
Levi Botelho,

1
Funziona per me in IE10 e Chrome 27. Amico, sei il mio eroe spaventoso!
BrainSlugs83

3
@LeviBotelho Mio male. Non c'era spazio attorno all'operatore.
utente

20
Inoltre, se usi Less, è meglio compilare un file con lessc --strict-math=onmeno per non valutare l'espressione all'interno di calc- solo un problema che ho affrontato e trascorso molto tempo (a partire da Less 2.0.0)
Dmitry Wojciechowski

34
Si noti che gli spazi intorno al segno meno non sono opzionali: 100%-18px, 100%- 18px, e 100% -18pxnon ha funzionato nei browser che ho provato con.
nisetama,

71

Per un approccio un po 'diverso potresti usare qualcosa di simile nell'elenco:

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

Funziona finché ha il contenitore principale position: relative;


1
grazie uomo. il contenitore genitore position: relative;mi stava facendo inciampare.
gthmb,

Per coloro che potrebbero chiedersi come me: la posizione deve essere absolutenel contenitore del bambino, non può esserlo relative.
Greg

Continua (scusate): tuttavia il genitore deve solo posizionarsi (può absoluteanche essere ) e deve essere impostato anche al 100% di altezza.
Greg,

1
Sfortunatamente, non funziona su Safari iOS 8. (Testato OK su browser stock Android 4.1 e FF 34 standard) :-(
Greg

Ciò potrebbe funzionare in alcuni casi, ma potrebbe anche causare alcuni problemi, poiché gli elementi posizionati in modo assoluto vengono rimossi dal flusso normale, vedere stackoverflow.com/a/12821537/4173303 .
Christophe Weis,

26

Uso Jquery per questo

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

quindi associo il ridimensionamento della finestra per ricalcolarlo ogni volta che viene ridimensionata la finestra del browser (se la dimensione del contenitore viene modificata con il ridimensionamento della finestra)

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

12
@puffpio, sicuramente JS è un modo per raggiungere questo obiettivo caso per caso. Ma come ho detto, sto cercando di rendere generico il CSS, da applicare su più pagine (che ereditano da una pagina master, per inciso). Quindi preferirei non usare JS. Ma grazie per la risposta.
MegaMatt

7
Non inserire il tuo stile in JavaScript.
Greg

8
@greg, sarebbe d'aiuto se CSS avesse alcune funzionalità più utili. Alcune cose per cui devi fare degli hack sono ridicole.
Jonathan.

1
@puffpio Bella soluzione davvero. Ma gli eventi vincolanti sulla finestra non sono una buona soluzione per me. Se la mia pagina contiene 3-4 o più elementi del genere, devo aggiornare l'altezza e la larghezza di ciascun elemento nel gestore di ridimensionamento della finestra. Questo sarebbe un po 'più lento della soluzione CSS.
sachinjain024,

1
"Non inserire il tuo xyz in JavaScript" è come dire "non supportare l'80% del mercato dei browser".
Beejor,

16

Non definire l'altezza come percentuale, basta impostare top=0e bottom=0, in questo modo:

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

Potresti spiegare perché non impostare l'altezza su una percentuale?
Shrikant Sharat,

@ShrikantSharat Fa parte delle specifiche di formattazione visiva per elementi assolutamente posizionati. Questa soluzione sfrutta la possibilità 5., "'height' è 'auto', 'top' e 'bottom' non sono 'auto', quindi vengono impostati i valori 'auto' per 'margin-top' e 'margin-bottom' a 0 e risolvi per "altezza" ". Il browser può calcolare l'altezza dell'elemento perché sa quanto deve essere lontano dalla parte superiore e inferiore dell'elemento principale.
Ross Allen,

Questo non sembra funzionare, almeno in Firefox. Anche con tutti gli elementi padre impostati su height:100%e display:block. Altrimenti sarebbe una soluzione molto elegante. È interessante notare che margin:autonon riesce anche a centrare verticalmente un oggetto a larghezza fissa, anche se funziona bene in orizzontale.
Beejor,

8

Presumendo un'altezza dell'intestazione di 17 px

Elenco css:

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

Header css:

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

Sì, è quello a cui stavo arrivando.
dclowd9901,

1
Non ha funzionato abbastanza bene come avevo sperato. La mia lista non ordinata viene avviata sotto quella div dell'intestazione. Il div dell'intestazione sta occupando spazio nel contenitore, quindi mettere la parte superiore del padiglione di 17px nell'elenco lo spingerà giù di 17px da dove è già nella foto sopra, non 17px dalla parte superiore del div del contenitore. Ecco una foto di ciò che ottengo con il CSS indicato nella risposta sopra: i41.tinypic.com/mcuk1x.jpg . Apprezzo lo sforzo, però, e se c'è qualcosa che pensi mi manchi, per favore fatemelo sapere. A proposito, ho un overflow: auto anche nell'elenco non ordinato.
MegaMatt

2
Sarebbe molto più facile risolvere questo problema se hai pubblicato CSS reali in modo che possiamo vedere esattamente quali interazioni stanno accadendo. Un'altra cosa che potresti provare è il margine superiore negativo sul tuo ul. ul { margin-top: -17px; }
ghoppe,

7
  1. Usa i margini negativi sull'elemento su cui desideri meno i pixel. (elemento desiderato)
  2. Rendere overflow:hidden; l'elemento contenente
  3. Passa overflow:auto;all'elemento desiderato.

Ha funzionato per me!


3
Questo ha funzionato come un incantesimo per me (non avevo nemmeno bisogno di cambiare l'overflow). Ottima soluzione, grazie!
Aaj,

1
Assolutamente fantastico! Mi è piaciuto conoscere la popolare soluzione "calc CSS", ma è molto più semplice e ha un supporto browser più ampio. Margini negativi in ​​perfetto!
Simon Steinberger,

Questa è una soluzione molto elegante e compatibile. Lo svantaggio principale è che l'elemento deve avere un'altezza fissa. Altrimenti dovresti usare JS o centrarlo calc()in fase di esecuzione. Ma per molti casi questo non dovrebbe essere un problema. Un'altra cosa da tenere a mente è che l'uso di molti valori negativi per margini, riempimento e offset può creare confusione quando si esegue il debug del codice in un secondo momento, quindi provare a mantenere le cose semplici.
Beejor,

5

Prova il dimensionamento delle scatole. Per l'elenco:

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;

Per l'intestazione:

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

Ovviamente, il contenitore padre dovrebbe avere qualcosa del tipo:

position: relative;

3

Un altro modo per raggiungere lo stesso obiettivo: scatole flessibili . Trasforma il contenitore in una scatola flessibile a colonna, quindi hai tutta la libertà di consentire ad alcuni elementi di avere dimensioni fisse (comportamento predefinito) o di riempire / restringere lo spazio del contenitore (con flex-grow: 1 e flex- shrink: 1).

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

Vedi https://jsfiddle.net/2Lmodwxk/ (prova ad estendere o ridurre la finestra per notare l'effetto)

Nota: è inoltre possibile utilizzare la proprietà stenografia:

   flex:1 1 auto;

Credo che questa possa essere la migliore risposta oggi perché significa non dover specificare un'altezza impostata per l'intestazione div (di 18px nella mia domanda originale) e non dover sottrarre cose come il riempimento e il margine. Nessun pixel impostato e tutto si prende cura di se stesso.
MegaMatt il

2

Ho provato alcune delle altre risposte, e nessuna di esse ha funzionato come volevo. La nostra situazione era molto simile quando avevamo un'intestazione della finestra e la finestra era ridimensionabile con le immagini nel corpo della finestra. Volevamo bloccare le proporzioni del ridimensionamento senza dover aggiungere calcoli per tenere conto delle dimensioni fisse dell'intestazione e far sì che l'immagine riempisse il corpo della finestra.

Di seguito ho creato uno snippet molto semplice che mostra ciò che abbiamo finito facendo che sembra funzionare bene per la nostra situazione e dovrebbe essere compatibile con la maggior parte dei browser.

Sul nostro elemento finestra abbiamo aggiunto un margine di 20 px che contribuisce al posizionamento rispetto ad altri elementi sullo schermo, ma non contribuisce alla "dimensione" della finestra. L'intestazione della finestra viene quindi posizionata in modo assoluto (il che la rimuove dal flusso di altri elementi, quindi non causerà lo spostamento di altri elementi come l'elenco non ordinato) e la sua parte superiore viene posizionata -20px che posiziona l'intestazione all'interno del margine della finestra. Alla fine il nostro elemento ul viene aggiunto alla finestra e l'altezza può essere impostata al 100%, il che farà sì che riempia il corpo della finestra (escluso il margine).

*,*: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

Grazie, ho risolto il mio con il tuo aiuto, modificandolo un po 'poiché voglio un div 100% larghezza 100% altezza (meno altezza di una barra inferiore) e nessun scorrimento sul corpo (senza hack / nascondere le barre di scorrimento).

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

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

Questo ha funzionato, oh sì ho messo un valore un po 'più grande su div. Regolato per l'altezza inferiore rispetto all'altezza della barra inferiore, altrimenti appare la barra di scorrimento verticale, ho regolato per essere il valore più vicino.

Quella differenza è perché uno degli elementi nell'area dinamica sta aggiungendo un ulteriore foro inferiore che non so come eliminare ... è un tag video (HTML5), si prega di notare che ho messo quel tag video con questo css ( quindi non c'è motivo per fare un buco in basso, ma lo fa):

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

L'obiettivo: avere un video che prende il 100% del browser (e si ridimensiona in modo dinamico quando il browser viene ridimensionato, ma senza alterare le proporzioni) meno uno spazio inferiore che uso per un div con alcuni testi, pulsanti, ecc. (E validatori w3c e css ovviamente).

EDIT: ho trovato il motivo, il tag video è come il testo, non un elemento a blocchi, quindi l'ho risolto con questo css:

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

Nota il display:block;tag sul video.


0

Non sono sicuro che questo funzioni nella tua particolare situazione, ma ho scoperto che il riempimento all'interno del div interno sposterà il contenuto all'interno di un div se il div contenente è di dimensioni fisse. Dovresti float o posizionare in modo assoluto il tuo elemento header, ma per il resto non l'ho provato per div di dimensioni variabili.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.