CSS: Ustawienie szerokości / wysokości jako Procent minus piksele


479

Próbuję utworzyć klasy CSS wielokrotnego użytku, aby uzyskać większą spójność i mniej bałaganu na mojej stronie, i utknąłem przy próbie standaryzacji jednej rzeczy, której często używam.

Mam kontener <div>, dla którego nie chcę ustawiać wysokości (ponieważ będzie się różnić w zależności od tego, gdzie na stronie się znajduje), a wewnątrz jest nagłówek <div>, a następnie nieuporządkowana lista elementów, wszystkie z zastosowaniem CSS im.

Wygląda to tak:

Widżet

Chcę, aby lista nieuporządkowana zajęła pozostałe miejsce w kontenerze <div>, wiedząc, że nagłówek <div>jest 18pxwysoki. Po prostu nie wiem, jak określić wysokość listy jako „wynik 100%minus 18px”.

Widziałem to pytanie zadawane w kilku innych kontekstach dotyczących SO, ale pomyślałem, że warto zadać jeszcze raz w mojej konkretnej sprawie. Czy ktoś ma jakieś porady w tej sytuacji?


6
Ustawić margines? __
kennytm

@KennyTM, zakładam, że sugerujesz, aby umieścić margines na mojej nieuporządkowanej liście, powiedzmy, 17px. Ale to popycha całą listę w dół; nie powoduje, że kurczy się, pozostając w pojemniku. Zasadniczo jego aktualna wysokość jest utrzymywana, ale została po prostu przesunięta w dół o 17 pikseli. To nie rozwiązuje mojego problemu, ale myślę, że to krok we właściwym kierunku, ponieważ widziałem inne podejścia online, które wykorzystywały tę technikę.
MegaMatt

Właśnie rozwiązałem ten problem w zamieszczonym tutaj pytaniu. stackoverflow.com/a/10420387/340947
Steven Lu

Odpowiedzi:


895

Zdaję sobie sprawę, że to stary post, ale biorąc pod uwagę, że nie zostało to zasugerowane, warto wspomnieć, że jeśli piszesz dla przeglądarek zgodnych z CSS3, możesz użyć calc:

height: calc(100% - 18px);

Warto zauważyć, że nie wszystkie przeglądarki obsługują obecnie standardową funkcję CSS3 calc (), dlatego może być wymagane wdrożenie specyficznych dla przeglądarki wersji funkcji, takich jak:

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

5
Tak, to na razie normalne.
Levi Botelho,

1
Działa dla mnie w IE10 i Chrome 27. Proszę pana, jesteś moim cholernym bohaterem!
BrainSlugs83

3
@LeviBotelho My bad. Nie ma miejsca wokół operatora.
użytkownik

20
Również jeśli użyjesz Less, lepiej skompiluj plik, lessc --strict-math=onaby mniej nie oceniać wyrażenia wewnątrz calc- to tylko problem, z którym się spotkałem i spędziłem dużo czasu (od Less 2.0.0)
Dmitry Wojciechowski

34
Należy pamiętać, że obowiązuje na całym znakiem minus nie są opcjonalne: 100%-18px, 100%- 18px, i 100% -18pxnie działa w przeglądarkach I testowanych.
nisetama,

71

Aby uzyskać nieco inne podejście, możesz użyć czegoś takiego na liście:

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

Działa to tak długo, jak ma kontener nadrzędny position: relative;


1
dzięki stary. pojemnik nadrzędny position: relative;mnie potykał.
gthmb,

Dla tych, którzy mogą się zastanawiać jak ja: pozycja musi znajdować się absolutew dziecięcym pojemniku, nie może być relative.
Greg

Kontynuacja (przepraszam): Jednak rodzic potrzebuje tylko pozycjonowania (może być absoluterównież) i musi być również ustawiony na 100% wysokości.
Greg

1
Niestety nie działa na Safari iOS 8. (Testowane OK na standardowej przeglądarce Androida 4.1 i standardowym FF 34) :-(
Greg

Może to działać w niektórych przypadkach, ale może również powodować pewne problemy, ponieważ absolutnie pozycjonowane elementy są usuwane z normalnego przepływu, patrz stackoverflow.com/a/12821537/4173303 .
Christophe Weis

26

Używam do tego Jquery

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

następnie łączę zmianę rozmiaru okna, aby ponownie go skalować za każdym razem, gdy zmienia się rozmiar okna przeglądarki (jeśli rozmiar kontenera zmieni się wraz ze zmianą rozmiaru okna)

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

12
@puffpio, Z pewnością JS jest sposobem na osiągnięcie tego indywidualnie dla każdego przypadku. Ale, jak powiedziałem, staram się, aby CSS był ogólny, aby można go było stosować na wielu stronach (nawiasem mówiąc, dziedzicząc po stronie wzorcowej). Więc wolałbym nie używać JS. Ale dzięki za odpowiedź.
MegaMatt

7
Nie umieszczaj swojego stylu w JavaScript.
Greg

8
@greg, dobrze byłoby, gdyby CSS miał kilka bardziej przydatnych funkcji. Niektóre rzeczy, dla których musisz robić włamania, są absurdalne.
Jonathan.

1
@puffpio Rzeczywiście fajne rozwiązanie. Ale wiązanie zdarzeń w oknie nie jest dla mnie dobrym rozwiązaniem. Jeśli moja strona zawiera 3-4 lub więcej takich elementów, muszę zaktualizować wysokość i szerokość każdego elementu w module obsługi zmiany rozmiaru okna. Byłoby to trochę wolniejsze niż rozwiązanie CSS.
sachinjain024

1
„Nie umieszczaj xyz w JavaScript” to jak „nie obsługuj 80% rynku przeglądarek”.
Beejor

16

Nie definiuj wysokości jako procentu, po prostu ustaw top=0i bottom=0, tak:

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

Czy możesz wyjaśnić, dlaczego nie ustawić wysokości na wartość procentową?
Shrikant Sharat 21.04.13

@ShrikantSharat Jest to część specyfikacji formatowania wizualnego dla absolutnie pozycjonowanych elementów. To rozwiązanie wykorzystuje możliwość 5., „wysokość” to „auto”, „góra” i „dół” nie są „auto”, następnie ustawiane są wartości „auto” dla „marginesu u góry” i „marginesu u dołu” na 0 i rozwiązać dla „wysokość” ”. Przeglądarka może obliczyć wysokość elementu, ponieważ wie, jak daleko musi być od góry i dołu elementu nadrzędnego.
Ross Allen,

Wydaje się, że to nie działa, przynajmniej w przeglądarce Firefox. Nawet przy wszystkich elementach nadrzędnych ustawionych na height:100%i display:block. W przeciwnym razie byłoby to bardzo eleganckie rozwiązanie. Co ciekawe, margin:autonie można również wyśrodkować obiektu o stałej szerokości w pionie, nawet jeśli działa dobrze w poziomie.
Beejor

8

Zakładając wysokość nagłówka 17 pikseli

Lista css:

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

Nagłówek css:

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

Tak, o to mi chodziło.
dclowd9901

1
To nie działało tak dobrze, jak się spodziewałem. Moja lista nieuporządkowana jest uruchamiana pod tym nagłówkiem div. Nagłówek div zajmuje miejsce w kontenerze, więc umieszczenie dopełniacza na górze 17px na liście po prostu popchnie go w dół 17px z miejsca, w którym jest już na powyższym obrazku, a nie 17px od góry div pojemnika. Oto zdjęcie tego, co otrzymuję dzięki CSS podanemu w odpowiedzi powyżej: i41.tinypic.com/mcuk1x.jpg . Doceniam jednak wysiłek, a jeśli uważasz, że czegoś brakuje, daj mi znać. Przy okazji mam przepełnienie: auto również na liście nieuporządkowanej.
MegaMatt

2
O wiele łatwiej byłoby rozwiązać ten problem, jeśli opublikowałeś rzeczywisty css, abyśmy mogli dokładnie zobaczyć, jakie interakcje mają miejsce. Inną rzeczą, którą możesz spróbować, jest ujemna górna marża na twojej ul. ul { margin-top: -17px; }
ghoppe

7
  1. Użyj ujemnych marginesów na elemencie, który chcesz pomniejszyć o piksele. (pożądany element)
  2. Zrób overflow:hidden;element zawierający
  3. Włącz overflow:auto;żądany element.

To zadziałało dla mnie!


3
To działało jak urok dla mnie (nawet nie musiałem zmieniać przelewu). Świetne rozwiązanie, dziękuję!
Aaj

1
Niesamowite! Z przyjemnością zapoznałem się z popularnym rozwiązaniem „CSS calc”, ale jest to o wiele prostsze i ma szerszą obsługę przeglądarki. Negatywne marże w idealnym stanie!
Simon Steinberger

To bardzo eleganckie i kompatybilne rozwiązanie. Głównym minusem jest to, że element musi mieć stałą wysokość. W przeciwnym razie musisz użyć JS lub calc()wyśrodkować go w czasie wykonywania. Ale w wielu przypadkach nie powinno to stanowić problemu. Inną rzeczą, o której należy pamiętać, jest to, że stosowanie wielu ujemnych wartości marginesów, wypełnienia i przesunięć może powodować zamieszanie podczas debugowania kodu później, więc staraj się zachować prostotę.
Beejor

5

Spróbuj zmienić rozmiar pudełka. Aby uzyskać listę:

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;

Dla nagłówka:

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

Oczywiście kontener nadrzędny powinien mieć coś takiego:

position: relative;

3

Kolejny sposób na osiągnięcie tego samego celu: elastyczne pudełka . Ustaw kontener jako elastyczne pole kolumnowe, a wtedy będziesz mieć swobodę pozwalania niektórym elementom mieć stały rozmiar (zachowanie domyślne) lub wypełniać / zmniejszać do przestrzeni kontenera (z Flex-Grow: 1 i Flex- kurczenie się: 1).

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

Zobacz https://jsfiddle.net/2Lmodwxk/ (spróbuj rozszerzyć lub zmniejszyć okno, aby zauważyć efekt)

Uwaga: możesz także użyć właściwości skrótu:

   flex:1 1 auto;

Wierzę, że może to być najlepsza odpowiedź dzisiaj, ponieważ oznacza to, że nie musisz określać wysokości div div nagłówka (18px w moim pierwotnym pytaniu) i oznacza to, że nie musisz odejmować takich rzeczy, jak dopełnianie i margines. Brak ustawionych pikseli i wszystko załatwia się samo.
MegaMatt,

2

Próbowałem kilku innych odpowiedzi i żadna z nich nie działała tak, jak chciałem. Nasza sytuacja była bardzo podobna, gdy mieliśmy nagłówek okna, a okno można było zmieniać za pomocą obrazów w bryle okna. Chcieliśmy zablokować proporcje zmiany rozmiaru bez konieczności dodawania obliczeń, aby uwzględnić stały rozmiar nagłówka i nadal mieć obraz wypełniający bryłę okna.

Poniżej stworzyłem bardzo prosty fragment, który pokazuje, co zrobiliśmy, co wydaje się działać dobrze w naszej sytuacji i powinno być kompatybilne z większością przeglądarek.

W naszym elemencie okna dodaliśmy margines 20px, który przyczynia się do pozycjonowania względem innych elementów na ekranie, ale nie wpływa na „rozmiar” okna. Nagłówek okna jest następnie pozycjonowany absolutnie (co usuwa go z przepływu innych elementów, więc nie spowoduje przesunięcia innych elementów, takich jak lista nieuporządkowana), a jego góra jest ustawiona na -20px, co umieszcza nagłówek wewnątrz marginesu okna. Na koniec nasz element ul jest dodawany do okna, a wysokość można ustawić na 100%, co spowoduje wypełnienie bryły okna (bez marginesu).

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

Dzięki, rozwiązałem mój z twoją pomocą, poprawiłem go trochę, ponieważ chcę div 100% szerokości 100% wysokości (mniejsza wysokość dolnego paska) i brak przewijania na ciele (bez hack / ukrywania pasków przewijania).

W przypadku 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;
}

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

To załatwiło sprawę, o tak, dodałem wartość div nieco lepiej dostosowaną do dolnej niż do wysokości dolnego paska, w przeciwnym razie pojawi się pionowy pasek przewijania, dostosowałem się do najbliższej wartości.

Różnica polega na tym, że jednym z elementów w obszarze dynamicznym jest dodanie dodatkowego dolnego otworu, którego nie wiem, jak się go pozbyć ... jest to tag wideo (HTML5), pamiętaj, że umieściłem ten tag wideo w tym css ( więc nie ma powodu, aby zrobić dolną dziurę, ale tak się dzieje):

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

Cel: mieć film, który zajmuje 100% przeglądarki (i zmienia się dynamicznie, gdy przeglądarka jest zmieniana, ale bez zmiany proporcji), mniej miejsca na dole, którego używam dla div z niektórymi tekstami, przyciskami itp. (I walidatory oczywiście w3c i css).

EDYCJA: Znalazłem przyczynę, tag wideo jest jak tekst, a nie element blokowy, więc naprawiłem to za pomocą tego css:

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

Zwróć uwagę display:block;na tag wideo.


0

Nie jestem pewien, czy to zadziała w twojej konkretnej sytuacji, ale odkryłem, że wypełnienie wewnętrznego div spowoduje wypchnięcie zawartości wewnątrz div, jeśli zawierający div ma stały rozmiar. Musiałbyś albo unosić, albo bezwzględnie pozycjonować element nagłówka, ale inaczej nie próbowałem tego dla div div o zmiennej wielkości.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.