CSS: Mengatur lebar / tinggi sebagai Persentase minus piksel

479

Saya mencoba membuat beberapa kelas CSS yang dapat digunakan kembali untuk konsistensi yang lebih baik dan lebih sedikit kekacauan di situs saya, dan saya terjebak dalam mencoba untuk membakukan satu hal yang sering saya gunakan.

Saya memiliki wadah <div>yang tidak ingin saya atur ketinggiannya (karena akan berbeda-beda tergantung di mana situs itu berada), dan di dalamnya ada header <div>, dan kemudian daftar item yang tidak berurutan , semua dengan CSS diterapkan ke mereka.

Ini terlihat sangat seperti ini:

Widget

Saya ingin daftar unordered untuk mengambil ruang yang tersisa dalam wadah <div>, mengetahui bahwa header <div>adalah 18pxtinggi. Saya hanya tidak tahu bagaimana menentukan tinggi daftar sebagai "hasil 100%minus 18px".

Saya telah melihat pertanyaan ini ditanyakan dalam beberapa konteks lain pada SO, tetapi saya pikir akan layak untuk bertanya lagi untuk kasus khusus saya. Adakah yang punya saran dalam situasi ini?

MegaMatt
sumber
6
Tentukan margin? __
kennytm
@ KennyTM, saya berasumsi Anda menyarankan saya menempatkan margin-top pada daftar unordered saya, katakanlah, 17px. Tetapi ini hanya mendorong seluruh daftar ke bawah; itu tidak menyebabkan menyusut untuk tetap berada di wadah. Pada dasarnya, tinggi saat ini dipertahankan, tetapi hanya didorong turun sebesar 17px. Ini tidak menyelesaikan masalah saya, tetapi saya pikir ini adalah langkah ke arah yang benar karena saya telah melihat pendekatan online lain yang menggunakan teknik ini.
MegaMatt
Saya baru saja memecahkan masalah ini dalam pertanyaan yang saya posting di sini. stackoverflow.com/a/10420387/340947
Steven Lu
kemungkinan rangkap dari CSS Bagaimana mengatur tinggi div 100% dikurangi nPx
200_success

Jawaban:

895

Saya menyadari ini adalah posting lama, tetapi mengingat bahwa itu belum disarankan, perlu disebutkan bahwa jika Anda menulis untuk browser yang mendukung CSS3, Anda dapat menggunakan calc:

height: calc(100% - 18px);

Perlu dicatat bahwa tidak semua browser saat ini mendukung fungsi standar CSS3 calc (), jadi mengimplementasikan versi browser spesifik dari fungsi tersebut mungkin diperlukan seperti berikut:

/* Firefox */
height: -moz-calc(100% - 18px);
/* WebKit */
height: -webkit-calc(100% - 18px);
/* Opera */
height: -o-calc(100% - 18px);
/* Standard */
height: calc(100% - 18px);
Levi Botelho
sumber
5
Ya itu normal untuk saat ini.
Levi Botelho
1
Bekerja untuk saya di IE10, dan Chrome 27. Anda tuan, adalah pahlawan saya yang menakutkan!
BrainSlugs83
3
@LeviBotelho Badaku. Tidak memiliki ruang di sekitar operator.
pengguna
20
Juga jika Anda menggunakan Less, Anda sebaiknya mengkompilasi file lessc --strict-math=onagar kurang untuk tidak mengevaluasi ekspresi di dalam calc- hanya masalah yang saya hadapi dan menghabiskan banyak waktu (pada Less 2.0.0)
Dmitry Wojciechowski
34
Perhatikan bahwa ruang di sekitar tanda minus tidak opsional: 100%-18px, 100%- 18px, dan 100% -18pxtidak bekerja di browser saya diuji dengan.
nisetama
71

Untuk sedikit pendekatan yang berbeda, Anda dapat menggunakan sesuatu seperti ini pada daftar:

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

Ini berfungsi selama wadah induk memiliki position: relative;

Nicolas Galler
sumber
1
Terima kasih sobat. wadah orangtua sedang position: relative;membuatku tersandung.
gthmb
Bagi mereka yang mungkin bertanya-tanya seperti saya: posisi harus ada absolutedalam wadah anak, itu tidak mungkin relative.
Greg
Lanjutan (maaf): Namun orang tua hanya perlu posisi (bisa absolutejuga), dan perlu diatur ke ketinggian 100% juga.
Greg
1
Sayangnya, ini tidak berfungsi di Safari iOS 8. (Diuji OK pada browser Android 4.1 dan standar FF 34) :-(
Greg
Ini mungkin berfungsi dalam beberapa kasus, tetapi juga dapat menyebabkan beberapa masalah, karena elemen yang diposisikan benar-benar dihapus dari aliran normal, lihat stackoverflow.com/a/12821537/4173303 .
Christophe Weis
26

Saya menggunakan Jquery untuk ini

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

maka saya mengikat ukuran jendela untuk recalc itu setiap kali jendela browser diubah ukurannya (jika ukuran kontainer diubah dengan ukuran jendela)

$(window).resize(function() { setSizes(); });
puffpio
sumber
12
@puffpio, Tentu saja JS adalah cara untuk mencapai ini berdasarkan kasus per kasus. Tetapi seperti yang saya katakan, saya mencoba membuat CSS generik, untuk diterapkan di beberapa halaman (yang mewarisi dari halaman master, secara tidak sengaja). Jadi saya lebih suka tidak menggunakan JS. Tapi terima kasih atas jawabannya.
MegaMatt
7
Jangan masukkan gaya Anda ke dalam JavaScript.
Greg
8
@reg, baik itu akan membantu jika CSS memiliki beberapa fitur yang lebih bermanfaat. Beberapa hal yang harus Anda lakukan sebagai peretasan adalah konyol.
Jonathan.
1
@puffpio Solusi yang bagus memang. Tetapi mengikat acara di jendela bukan solusi yang baik bagi saya. Jika halaman saya memiliki 3-4 atau lebih elemen seperti itu saya harus memperbarui tinggi dan lebar setiap elemen di window handler ukuran. Ini akan sedikit lebih lambat daripada solusi CSS.
sachinjain024
1
"Jangan letakkan xyz Anda di dalam JavaScript" seperti mengatakan "jangan mendukung 80% pasar browser".
Beejor
16

Jangan mendefinisikan tinggi sebagai persentase, cukup atur top=0dan bottom=0, seperti ini:

#div {
   top: 0; bottom: 0;
   position: absolute;
   width: 100%;
}
kaleazy
sumber
Bisakah Anda jelaskan mengapa tidak menetapkan tinggi menjadi satu persen?
Shrikant Sharat
@ShrikantSharat Ini adalah bagian dari spesifikasi pemformatan visual untuk elemen yang benar-benar diposisikan. Solusi ini memanfaatkan kemungkinan 5., "'tinggi' adalah 'otomatis', 'atas' dan 'bawah' bukan 'otomatis', maka nilai 'otomatis' untuk 'margin-top' dan 'margin-bottom' ditetapkan ke 0 dan pecahkan untuk 'tinggi' ". Browser dapat menghitung ketinggian elemen karena tahu seberapa jauh dari atas dan bawah dari induknya.
Ross Allen
Ini sepertinya tidak berhasil, setidaknya di Firefox. Bahkan dengan semua elemen induk diatur ke height:100%dan display:block. Kalau tidak, itu akan menjadi solusi yang sangat elegan. Menariknya, margin:autojuga gagal memusatkan objek dengan lebar tetap secara vertikal, meskipun berfungsi dengan baik secara horizontal.
Beejor
8

Menganggap tinggi header 17px

Daftar css:

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

Header css:

height: 17px;
float: left;
width: 100%;
ghoppe
sumber
Yap, itulah yang saya maksudkan.
dclowd9901
1
Itu tidak bekerja dengan baik seperti yang saya harapkan. Daftar unordered saya sedang dimulai di bawah div header itu. Header div mengambil ruang dalam wadah, sehingga menempatkan padding-top 17px pada daftar hanya akan mendorongnya ke bawah 17px dari tempat yang sudah ada dalam gambar di atas, bukan 17px dari atas div wadah. Berikut ini foto yang saya dapatkan dengan CSS yang diberikan dalam jawaban di atas: i41.tinypic.com/mcuk1x.jpg . Saya menghargai upaya ini, dan jika ada sesuatu yang Anda pikir saya lewatkan, beri tahu saya. Btw, saya mengalami overflow: otomatis pada daftar yang tidak berurutan juga.
MegaMatt
2
Akan jauh lebih mudah mengatasi masalah ini jika Anda memposting css yang sebenarnya sehingga kami dapat melihat interaksi apa yang sedang terjadi. Hal lain yang mungkin Anda coba adalah margin atas negatif pada ul Anda. ul { margin-top: -17px; }
ghoppe
7
  1. Gunakan margin negatif pada elemen yang ingin Anda kurangi pikselnya. (elemen yang diinginkan)
  2. Buat overflow:hidden;pada elemen yang mengandung
  3. Beralih ke overflow:auto;elemen yang diinginkan.

Itu berhasil untuk saya!

desbest
sumber
3
Ini bekerja seperti pesona bagi saya (saya bahkan tidak perlu mengubah overflow). Solusi hebat, terima kasih!
Aaj
1
Sangat luar biasa! Senang belajar tentang solusi "CSS calc" yang populer, tetapi ini jauh lebih sederhana dan memiliki dukungan browser yang lebih luas. Margin negatif sempurna!
Simon Steinberger
Ini adalah solusi yang sangat elegan dan kompatibel. Kelemahan utama adalah bahwa elemen harus memiliki ketinggian tetap. Kalau tidak, Anda harus menggunakan JS atau calc()memusatkannya pada saat runtime. Tetapi untuk banyak kasus ini seharusnya tidak menjadi masalah. Hal lain yang perlu diingat adalah bahwa menggunakan banyak nilai negatif untuk margin, padding, dan offset dapat menyebabkan kebingungan ketika men-debug kode nanti, jadi cobalah untuk menjaga hal-hal sederhana.
Beejor
5

Coba ukuran kotak. Untuk daftar:

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;

Untuk tajuk:

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

Tentu saja, wadah induk harus memiliki sesuatu seperti:

position: relative;
Cahaya
sumber
3

Cara lain untuk mencapai tujuan yang sama: kotak fleksibel . Jadikan wadah sebagai kotak fleksibel kolom, dan kemudian Anda memiliki semua kebebasan untuk memungkinkan beberapa elemen memiliki ukuran tetap (perilaku default) atau untuk mengisi / mengecilkan ke ruang wadah (dengan pertumbuhan-tumbuh: 1 dan lentur- menyusut: 1).

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

Lihat https://jsfiddle.net/2Lmodwxk/ (coba perpanjang atau kurangi jendela untuk melihat efeknya)

Catatan: Anda juga dapat menggunakan properti singkatan:

   flex:1 1 auto;
tarulen
sumber
Saya percaya ini mungkin jawaban terbaik hari ini karena itu berarti tidak harus menentukan tinggi yang ditetapkan untuk div header (dari 18px dalam pertanyaan awal saya), dan itu berarti tidak harus mengurangi hal-hal seperti padding dan margin. Tidak ada piksel yang ditetapkan, dan semuanya mengurus dirinya sendiri.
MegaMatt
2

Saya mencoba beberapa jawaban lain, dan tidak ada yang bekerja seperti yang saya inginkan. Situasi kami sangat mirip dengan header jendela dan jendela dapat diubah ukurannya dengan gambar di badan jendela. Kami ingin mengunci rasio aspek dari pengubahan ukuran tanpa perlu menambahkan perhitungan untuk memperhitungkan ukuran tetap dari header dan masih memiliki gambar yang mengisi tubuh jendela.

Di bawah ini saya membuat cuplikan yang sangat sederhana yang menunjukkan apa yang akhirnya kami lakukan yang tampaknya bekerja dengan baik untuk situasi kami dan harus kompatibel di sebagian besar browser.

Pada elemen jendela kami, kami menambahkan margin 20px yang berkontribusi pada penentuan posisi relatif terhadap elemen lain di layar, tetapi tidak berkontribusi pada "ukuran" jendela. Window-header kemudian diposisikan secara absolut (yang menghilangkannya dari aliran elemen lain, sehingga tidak akan menyebabkan elemen lain seperti daftar yang tidak berurutan digeser) dan atasnya diposisikan -20px yang menempatkan header di dalam margin dari jendela. Akhirnya elemen ul kami ditambahkan ke jendela, dan tingginya dapat diatur ke 100% yang akan membuatnya mengisi tubuh jendela (tidak termasuk margin).

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

TJ Rockefeller
sumber
1

Terima kasih, saya menyelesaikan masalah saya dengan bantuan Anda, mengubahnya sedikit karena saya ingin div 100% lebar 100% heigth (kurang tinggi dari bilah bawah) dan tidak ada gulir di badan (tanpa peretasan / menyembunyikan bilah gulir).

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

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

Itu berhasil, oh ya saya menaruh nilai sedikit lebih hebat pada div.adjusted untuk bottom daripada untuk bottom bar tinggi, kalau tidak scrollbar vertikal muncul, saya disesuaikan menjadi nilai terdekat.

Perbedaannya adalah karena salah satu elemen di area dinamis adalah menambahkan lubang bawah tambahan yang saya tidak tahu bagaimana cara menghilangkannya ... itu adalah tag video (HTML5), harap dicatat saya meletakkan tag video itu dengan css ini ( jadi tidak ada alasan untuk itu membuat lubang bawah, tetapi itu memang):

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

Tujuannya: Memiliki video yang mengambil 100% browser (dan mengubah ukuran secara dinamis ketika browser diubah ukurannya, tetapi tanpa mengubah rasio aspek) kurang ruang bawah yang saya gunakan untuk div dengan beberapa teks, tombol, dll (dan validator w3c & css tentu saja).

EDIT: Saya menemukan alasannya, tag video seperti teks, bukan elemen blok, jadi saya memperbaikinya dengan css ini:

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

Perhatikan display:block;tag pada video.

Claudio
sumber
0

Saya tidak yakin apakah ini berfungsi dalam situasi khusus Anda, tetapi saya telah menemukan bahwa bantalan pada div bagian dalam akan mendorong konten di dalam div jika div yang berisi ukuran tetap. Anda harus mengapung atau benar-benar memposisikan elemen header Anda, tetapi jika tidak, saya belum mencoba ini untuk div ukuran variabel.

dclowd9901
sumber