CSS Grid: Mengetik tata letak majalah 20-baris yang responsif


Baru-baru ini, saya mengerjakan implementasi modern dari blog roll (daftar blog eksternal yang bermanfaat / menarik). Idenya adalah untuk memberi pembaca pilihan posting terbaru di blog-blog ini, yang dikemas dalam tata letak majalah, dan bukan daftar kering tautan di sidebar.

Bagian termudah dari tugas ini adalah untuk mendapatkan daftar posting dan kutipannya (kutipan - teks pengantar sebelum kat) dari feed RSS favorit kami. Untuk melakukan ini, kami menggunakan plugin Feedzy lite WordPress , yang dapat menggabungkan beberapa feed menjadi satu daftar, diurutkan berdasarkan waktu - solusi ideal dalam kasus kami. Bagian yang sulit adalah membuat semuanya indah.

Antarmuka daftar standar plugin mungkin tidak berasa, jadi saya ingin menatanya sebagai situs web surat kabar atau majalah dengan campuran blok "terpilih" besar dan kecil.

Kedengarannya seperti kesempatan yang sempurna untuk menggunakan CSS Grid! Buat Tata Letak Kotak untuk tata letak yang berbeda, misalnya, satu lima kolom dan satu tiga kolom, lalu beralih di antara mereka menggunakan kueri media pada ukuran layar yang berbeda. Baik? Tetapi apakah kita benar-benar membutuhkan pertanyaan media ini, dan semua masalah ini dengan menentukan titik kontrol, jika Anda bisa menggunakan parameter Grid auto-fit, yang akan membuat grid adaptif untuk kita?

Gagasan ini tampak menggoda bagi saya, tetapi ketika saya mulai menambahkan elemen yang mencakup beberapa kolom grid ( bentang), grid mulai merayap keluar dari halaman pada layar sempit. Pertanyaan media sepertinya satu-satunya solusi. Tetapi saya menemukan sesuatu yang lebih baik!

Setelah mempelajari sejumlah artikel di CSS Grid, saya menemukan bahwa mereka terutama dibagi menjadi dua jenis:

  1. Cara membuat tata letak yang menarik dengan rentang, tetapi dengan jumlah kolom tertentu.
  2. Cara membuat tata letak adaptif pada Kotak, tetapi dengan kolom dengan lebar yang sama (mis. Tanpa bentang).

Saya ingin grid untuk mengimplementasikan ini dan itu: tata letak yang sepenuhnya adaptif menggunakan elemen multi-kolom yang mengubah ukuran secara adaptif.

Keindahannya adalah segera setelah Anda mulai memahami batasan-batasan kisi adaptif dan mengapa dan ketika rentang merusak kemampuan beradaptasi, mudah untuk membuat tata letak majalah dengan lusinan baris kode dan satu kueri media (atau bahkan tanpa mereka jika Anda ingin membatasi variasi bentang).

Berikut ini adalah perbandingan yang jelas dari plugin RSS dari kotak dan hasil karya kami (dapat diklik):


Ini adalah tata letak majalah yang sepenuhnya adaptif dengan blok berwarna "terpilih" yang secara dinamis beradaptasi dengan tata letak tergantung pada jumlah kolom. Halaman menampilkan sekitar 50 posting, tetapi kode tata letak tidak tergantung pada jumlah elemen. Anda dapat dengan mudah meningkatkan jumlah posting menjadi 100 dalam pengaturan plugin, dan tata letak akan tetap menarik hingga ke paling bawah.

Semua ini dicapai secara eksklusif melalui CSS dan hanya menggunakan satu permintaan media untuk menampilkan konten dalam satu kolom pada layar tersempit (kurang dari 460 piksel).

Apa yang paling luar biasa, seluruh tata letak hanya mengambil 21 baris CSS (tidak termasuk gaya umum situs). Namun, untuk mencapai fleksibilitas seperti itu menggunakan kode sangat sedikit, saya harus menyelam jauh ke kedalaman paling gelap dari CSS Grid dan belajar bagaimana untuk mengatasi beberapa keterbatasannya.

Kode tempat seluruh tata letak terletak sangat pendek, dan semuanya berkat kemegahan Kotak CSS:

.archive {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  grid-gap: 32px;
  grid-auto-flow: dense;
}

/*    */
.article:nth-child(31n + 1) {
  grid-column: 1 / -1;
}
.article:nth-child(16n + 2) {
  grid-column: -3 / -1;
}
.article:nth-child(16n + 10) {
  grid-column: 1 / -2;
}

/*     */
@media (max-width: 459px) {
  .archive {
    display: flex;
    flex-direction: column;
  }
}

Teknik yang dijelaskan dalam artikel ini dapat digunakan dengan aman untuk menyesuaikan dgn mode konten yang dihasilkan secara dinamis, apakah itu merupakan output dari widget posting terbaru, halaman arsip atau hasil pencarian.

Buat mesh adaptif


Saya membuat 17 elemen untuk menampilkan keragaman konten masa depan - berita utama, gambar, dan kutipan, dan dibungkus <div></div>

<div class="archive">
  <article class="article">
    <!--  -->
  </article>

  <!--  16  -->

</div>

Kode untuk mengubah elemen-elemen ini menjadi grid adaptif sangat kompak:

.archive {
  /*     - */
  display: grid;
  /*        ,       180 . */
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  /*     */
  grid-gap: 1em;
}

β†’ Demo di CodePen

Perhatikan bagaimana ketinggian garis secara otomatis menyesuaikan ke blok konten tertinggi di baris. Jika Anda mengubah lebar dalam demo dari tautan di atas, Anda akan melihat bahwa elemen bertambah dan berkurang secara otomatis dan jumlah kolom berubah dari 1 menjadi 5, masing-masing.

Di sini dalam aksi, kita melihat keajaiban Grid CSS disebutauto-fit. Kata kunci ini berfungsi bersamaan dengan fungsi yangminmax()diterapkangrid-template-columns.

Bagaimana itu bekerja


Tata letak lima kolom itu sendiri dapat diperoleh seperti ini:

.archive {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
}

Namun, ini menciptakan tata letak lima kolom yang membentang dan berkontraksi pada lebar layar yang berbeda, tetapi selalu tetap lima kolom, yang mengarah ke kolom yang sangat sempit pada layar kecil. Hal pertama yang terlintas dalam pikiran adalah menulis banyak pertanyaan media dan mendefinisikan kembali sebuah kisi dengan jumlah kolom yang berbeda. Itu akan berhasil, tetapi kata kunci auto-fitmelakukan semuanya secara otomatis.

Untuk auto-fitmenggunakan fungsi yang kita butuhkan minmax(). Jadi, kami memberi tahu browser seberapa banyak Anda dapat mengompres kolom, dan berapa banyak yang perlu direntangkan. Ketika salah satu batas tercapai, jumlah kolom bertambah atau berkurang.

.archive {
  grid-template-columns: repeat (auto-fit, minmax(180px, 1fr));
}

Dalam contoh ini, browser akan mencoba mengakomodasi kolom sebanyak lebar 180 piksel. Jika ada ruang berlebih, semua kolom akan mengembang, membaginya secara merata. Inilah yang menentukan artinya 1fr: untuk membuat ukuran kolom sama dengan fraksi ( fr aksi) dari lebar yang tersedia.

Jika Anda meregangkan jendela peramban, semua kolom akan tumbuh sama dengan bertambahnya ruang kosong. Segera setelah ruang yang baru ditemukan mencapai 180 piksel, kolom baru muncul di tempatnya. Dan jika Anda mengurangi jendela browser, semuanya terjadi sebaliknya, pas dengan grid sampai berubah menjadi tata letak satu kolom. Sihir!

β†’ Video demo

Dan semua kemampuan beradaptasi ini berkat satu baris kode. Baik keren?

Membuat rentang dengan "autoflow: padat"


Jadi, saat ini kami sudah memiliki kisi adaptif, itu semua elemennya - lebar yang sama. Tata letak koran atau majalah menyiratkan adanya blok yang dipilih, dalam konteks ini, yang akan mencakup dua, tiga, atau bahkan semua kolom yang tersedia.

Untuk membuat bentang multi-kolom, kita bisa menggunakan properti grid-column: spandi elemen-elemen yang harus menempati lebih banyak ruang. Misalkan kita ingin item daftar ketiga menjadi lebar dua kolom:

.article:nth-child(3) {
  grid-column: span 2;
}

Namun, setelah menambahkan bentang, banyak masalah mungkin muncul. Pertama, lubang dapat terbentuk di grid dalam kasus-kasus tersebut ketika elemen lebar tidak sesuai pada garisnya dan auto-fitmentransfernya ke yang berikut:


Ini mudah diperbaiki dengan menambahkan properti grid-auto-flow: denseke grid. Karena properti ini, browser memahami bahwa lubang perlu diisi dengan elemen lain. Ini menciptakan aliran di sekitar elemen yang lebih luas yang lebih sempit:


Harap dicatat: urutan elemen rusak, sekarang elemen keempat ada di depan yang ketiga. Sejauh yang saya tahu, ini tidak dapat dilewati, ini adalah salah satu batasan dari CSS Grid yang harus diterima.

Cara mengidentifikasi bentang


Ada beberapa cara untuk menentukan jumlah kolom yang harus ditempati suatu item. Cara termudah untuk diterapkan grid-columns: span [n]ke salah satu elemen, di mana njumlah kolom yang akan ditempati elemen. Elemen ketiga dalam tata letak kami memiliki properti terdaftar grid-column: span 2, yang menjelaskan mengapa lebarnya dua kali lebih besar dari elemen lainnya.

Untuk menggunakan metode lain, Anda harus menentukan garis kisi . Garis kisi diberi nomor sebagai berikut:


Garis kisi dapat ditunjukkan dari kiri ke kanan menggunakan angka positif (misalnya, 1, 2, 3), atau dari kanan ke kiri menggunakan angka negatif (-1, -2, -3). Mereka dapat digunakan untuk menempatkan elemen di grid menggunakan properti grid-column, seperti ini:

.grid-item {
  grid-column: ( ) / ( );
}

Jadi, garis kisi memperluas kemampuan kita untuk menentukan rentang. Fleksibilitas ditambahkan oleh kemampuan untuk mengganti nilai awal atau akhir dengan kata kunci span. Misalnya, blok biru tiga kolom pada contoh di atas dapat dibuat dengan menerapkan salah satu properti ini ke elemen grid kedelapan:

  • grid-column: 3 / 6
  • grid-column: -4 / -1
  • grid-column: 3 / span 3
  • grid-column: -4 / span 3
  • grid-column: span 3 / -1
  • dll.

Dalam kisi non-adaptif (mis., Dengan jumlah kolom tetap), masing-masing properti ini memberikan hasil yang sama (seperti pada contoh dengan blok biru di atas). Tetapi jika kisi tersebut adaptif dan jumlah kolom berubah, perbedaannya menjadi sangat nyata. Beberapa bentang merusak tata letak dengan pembungkus otomatis dihidupkan, yang membuatnya tampak bahwa kedua solusi ini tidak kompatibel. Untungnya, beberapa trik akan memungkinkan kita untuk menggabungkannya dengan aman.

Tapi pertama-tama, kita perlu memahami masalahnya.

Masalah Pengguliran Horisontal


Berikut adalah beberapa "item fitur" yang dibuat menggunakan metode garis grid (dapat diklik):


Di seluruh lebar (lima kolom), semuanya terlihat bagus, tetapi jika Anda mengurangi layar ke ukuran di mana harus ada dua kolom, tata letak rusak dengan cara ini:


Seperti yang Anda lihat, kisi kami telah kehilangan kemampuan beradaptasi dan, meskipun wadahnya menyusut, kisi itu mencoba mendukung kelima kolom. Untuk melakukan ini, ia terus mencoba lebar kolom yang sama dan akhirnya melampaui batas wadahnya ke kanan. Dari sini, gulir horizontal muncul.

Kenapa itu terjadi? Masalahnya adalah browser mencoba mematuhi petunjuk kami yang tepat untuk garis kisi. Pada lebar ini, auto-fitkisi - kisi hanya akan menampilkan dua kolom, tetapi sistem penomoran baris stack kami bertentangan dengan ini, merujuk secara khusus ke baris kelima. Kontradiksi ini menyebabkan kekacauan. Untuk menampilkan kisi dua kolom tersirat kami dengan benar, hanya angka 1, 2, 3 dan -3, -2, -1 yang dapat digunakan, seperti ini:


Tetapi jika salah satu elemen dari kisi kami berisi instruksi di grid-columnluar batas ini, katakanlah 4, 5 atau -6, browser akan menerima instruksi yang ambigu. Di satu sisi, kami meminta Anda untuk membuat kolom fleksibel secara otomatis (yang seharusnya - secara implisit - tetap dua pada lebar layar ini). Di sisi lain, kami secara eksplisit merujuk ke garis kisi, yang tidak dapat ada dalam format dua kolom. Ketika ada kontradiksi antara kolom implisit (otomatis) dan angka yang ditentukan secara eksplisit, kisi selalu lebih suka definisi eksplisit . Ini adalah bagaimana kolom yang tidak diinginkan dan melimpah horisontal muncul (apa yang mereka sebut kehilangan data CSS) Rentang, seperti nomor garis kisi, dapat membuat definisi kolom eksplisit. kisi-kolom: span 3 (elemen grid kedelapan dalam demo) memaksa kisi untuk secara eksplisit memiliki setidaknya tiga kolom, terlepas dari kenyataan bahwa kita menginginkan dua yang implisit.

Tampaknya satu-satunya pilihan adalah menggunakan kueri media untuk mengubah nilai grid-columnpada lebar yang diinginkan ... tapi jangan terburu-buru! Saya juga berpikir begitu pada awalnya. Tapi, setelah sedikit merenung dan bermain-main dengan pengaturan yang berbeda, saya menemukan bahwa ada beberapa cara untuk mengatasi masalah ini, berkat itu kami masih memiliki hanya satu permintaan media untuk perangkat tersempit.

Solusi


Ternyata, triknya adalah menentukan rentang menggunakan hanya nomor baris yang tersedia untuk kisi tersempit dari yang direncanakan untuk ditampilkan. Dalam hal ini, kita berbicara tentang kisi dua kolom (ingat, kami menggunakan kueri media untuk tampilan satu kolom). Dengan demikian, Anda dapat dengan aman menggunakan angka 1, 2, 3 dan pasangan negatifnya tanpa merusak kisi.

Pada awalnya saya berpikir bahwa saya akan membatasi diri pada lebar rentang dalam dua kolom menggunakan kombinasi angka-angka ini:

  • grid column: span 2
  • grid-column: 1 /3
  • grid-column: -3 / -1


Yang tetap dapat beradaptasi dengan sempurna hingga dua speaker:


Meskipun ini berfungsi , dari sudut pandang desain, ini adalah batasan yang serius, dan tidak terlalu cerah. Saya ingin membuat bentang dengan lebar tiga, empat atau bahkan lima kolom pada layar lebar. Tapi bagaimana caranya? Pikiran pertama saya adalah kembali ke pertanyaan media (omg, sulit untuk menghilangkan kebiasaan lama), tetapi saya masih mencoba untuk menghindari pendekatan ini dan melihat desain responsif dari sudut yang berbeda.

Melihat lagi daftar angka yang tersedia, saya tiba-tiba menyadari bahwa angka positif dan negatif dalam nilai awal dan akhir grid-columndapat digabungkan, misalnya 1/-3,2/-2. Tampaknya tidak ada yang menarik. Tapi itu tidak tampak seperti itu lagi ketika Anda memahami posisi garis setelah mengubah ukuran kisi: rentang mengubah lebar sesuai dengan lebar layar. Sejumlah peluang baru untuk rentang adaptif terbuka, khususnya, elemen yang menjangkau sejumlah kolom berbeda dengan perubahan lebar layar, tanpa kueri media apa pun.

Contoh pertama yang saya temukan adalah grid-column: 1/-1. Properti ini mengubah elemen menjadi banner dengan lebar penuh, mengisi semua kolom dari pertama hingga terakhir, bahkan ketika hanya ada satu kolom!

Menggunakangrid-column: 1/-2, Anda dapat membuat rentang "hampir penuh", yang mengisi semua kolom dari kiri ke kanan, kecuali yang terakhir. Dalam tata letak dua kolom, rentang tersebut secara adaptif berubah menjadi elemen biasa dalam satu kolom. Anehnya, ia bekerja bahkan ketika mengompresi tata letak menjadi satu kolom. (Tampaknya alasannya adalah bahwa grid tidak akan mengurangi elemen nol lebar dan karena itu tetap lebar satu kolom, seperti dalam kasus dengan grid-column: 1/1.) Saya berasumsi bahwa itu grid-column: 2/-1harus bekerja dengan cara yang sama, hanya meninggalkan satu kolom tersentuh di sebelah kiri, dan tidak di sebelah kanan . Ternyata hampir benar, ketika mengompresi tata letak ke satu kolom, masih terjadi overflow.

Lalu saya mencoba kombinasi1/-3. Ini bekerja dengan baik pada layar lebar - mengisi setidaknya tiga kolom - dan pada yang sempit - hanya mengisi satu. Saya berpikir bahwa dengan kisi dua kolom, sesuatu yang aneh akan berubah, karena sejak baris pertama kisi sama dengan garis di bawah angka -3. Yang mengejutkan saya, item tersebut ditampilkan dengan benar dalam satu kolom.

Setelah banyak percobaan, saya menemukan bahwa ada 11 nilai yang sesuai grid-columndari yang tersedia dalam kisi dua kolom. Tiga di antaranya bekerja bahkan dalam tata letak satu kolom. Tujuh lainnya bekerja dengan benar hingga dua kolom, dan untuk tampilan yang tepat dalam satu kolom mereka hanya membutuhkan satu permintaan media.

Berikut daftar lengkapnya:


Demonstrasi nilai kolom kotak adaptif pada berbagai ukuran layar dalam kisi fit otomatis. ( Demo )

Secara umum, meskipun rentang adaptif yang agak terbatas, ada banyak peluang.

  • 2/-2 - Kombinasi yang menarik, menciptakan bentang terpusat yang berfungsi hingga grid satu kolom!
  • 3/-1 - paling tidak berguna karena mengarah ke overflow bahkan pada dua kolom.
  • 3/-3 - kejutan yang menyenangkan.

Karena beragamnya nilai grid-columndari daftar ini, dimungkinkan untuk membuat tata letak yang menarik dan sepenuhnya responsif. Menggunakan kueri media tunggal untuk tampilan kolom tunggal tersempit, kita dapat mengelola sepuluh pola yang berbeda grid-column.

Permintaan media yang sama itu cukup sederhana, bahkan katakanlah secara langsung. Dalam contoh kami, ia bertanggung jawab untuk mengalihkan tampilan grid ke flexbox:

@media (max-width: 680px) {
  .archive {
    display: flex;
    flex-direction: column;
  }

  .article {
    margin-bottom: 2em;
  }
}

Inilah kisi terakhir, yang, seperti yang Anda perhatikan, sepenuhnya responsif - mulai dari satu hingga lima kolom (dapat diklik):


Penggunaan: nth-child () untuk mengulangi lebar dinamis


Untuk mengurangi kode saya menjadi dua lusin baris, saya menerapkan trik lain. Pemilih :nth-child(n)memungkinkan saya untuk mendesain sejumlah besar elemen sekaligus. Seluruh gagasan saya dengan bentang akan diterapkan ke banyak pos di umpan sehingga blok yang dipilih akan muncul di halaman secara teratur. Pertama, saya menulis daftar pemilih yang dipisahkan koma dengan nomor elemen yang jelas:

.article:nth-child(2),
.article:nth-child(18),
.article:nth-child(34),
.article:nth-child(50)  {
  background-color: rgba(128,0,64,0.8);
  grid-column: -3 / -1;
}

Dalam kecepatan, saya menyadari bahwa ini adalah proses yang sangat memakan waktu, terutama ketika Anda harus menyalin seluruh daftar kondisi ini untuk setiap elemen anak yang perlu diubah di dalam artikel - heading, tautan, dll. Selama prototyping, saya dipaksa untuk mengubah angka secara manual di setiap daftar ini setiap kali saya ingin bermain dengan posisi bentang. Proses yang membosankan dan rentan kesalahan.

Saat itulah saya menyadari bahwa Anda dapat memanfaatkan fitur keren dari pseudo-selector :nth-child: alih-alih nilai integer, masukkan ekspresi, misalnya :nth-child(2n+ 2), yang berarti setiap elemen anak kedua.

Ini adalah bagaimana saya digunakan :nth-child([])untuk membuat blok biru lebar penuh di kisi saya yang muncul di bagian atas halaman dan kemudian setengah jalan daftar:

.article:nth-child(31n + 1) {
  grid-column: 1 / -1;
  background: rgba(11, 111, 222, 0.5);
}

Sepotong kode dalam tanda kurung ( 31n + 1) bertanggung jawab untuk memilih tanggal 1, 32, 63, dll. elemen anak. Browser memulai loop dimulai dengan n = 0 ( 31 * 0 + 1 = 1), lalu n=1( 31 * 1 + 1 = 32), dan akhirnya n=2( 31 * 2 + 1 = 63). Dalam kasus terakhir, browser memahami bahwa tidak ada elemen anak ke-63, mengabaikan aturan, menghentikan siklus dan menerapkan aturan ke elemen 1 dan 32.

Saya melakukan sesuatu yang mirip dengan blok ungu yang muncul di sebelah kiri atau kanan di seluruh halaman:

.article:nth-child(16n + 2) {
  grid-column: -3 / -1;
  background: rgba(128, 0, 64, 0.8);
}

.article:nth-child(16n + 10) {
  grid-column: 1 / -2;
  background: rgba(128, 0, 64, 0.8);
}

Pemilih pertama adalah untuk blok ungu kiri. Ekspresi 16n + 2bertanggung jawab untuk menerapkan gaya ke setiap elemen grid ke-16, dimulai dengan yang kedua.

Selektor kedua adalah untuk blok ungu yang tepat. Intervalnya sama ( 16n), tetapi shiftnya berbeda ( 10). Akibatnya, blok-blok ini secara teratur ditemukan di sisi kanan grid, dalam elemen bernomor 10, 26, 42, dll.

Untuk gaya visual elemen-elemen ini, saya menggunakan trik lain untuk menghindari pengulangan kode. Untuk gaya umum blok ungu ( background-colormisalnya, jelas ), Anda dapat menggunakan satu pemilih:

.article:nth-child(8n + 2) {
  background: rgba(128, 0, 64, 0.8);
  /* Other shared syling */
}

Pemilih ini akan memilih item 2, 10, 18, 26, 34, 42, 50, dan lainnya. Dengan kata lain, ia memilih blok kiri dan kanan.

Ini bekerja karena 8n- ini persis setengah 16n, dan perbedaan shift dalam dua penyeleksi juga 8.

Kata terakhir


CSS Grid sekarang dapat digunakan untuk membuat jerat yang fleksibel dan responsif dengan kode minimal. Namun, jika Anda menghindari penggunaan kueri media retrograde, ada batasan signifikan pada penentuan posisi elemen dalam kisi.

Akan sangat keren untuk dapat membuat bentang yang tidak akan mengarah pada pengguliran horizontal dan limpahan pada layar kecil. Sekarang kita dapat memberi tahu browser: "Tolong buat grid adaptif," dan itu melakukannya dengan sangat baik. Tapi Anda hanya perlu menambahkan: "Oh, elemen grid ini direntangkan menjadi empat kolom, tolong," dan dia melambaikan pegangan ke layar sempit, memberikan preferensi pada permintaan untuk rentang empat kolom, daripada grid adaptif. Mungkin saja membuat grid melakukan yang sebaliknya, misalnya seperti ini:

.article {
  grid-column: span 3, autofit;
}

Masalah lain dengan grid responsif adalah baris terakhir. Mengubah lebar layar seringkali dapat menyebabkannya kosong. Saya mencoba untuk waktu yang lama untuk menemukan cara untuk meregangkan elemen terakhir dari grid ke kolom yang tersisa (masing-masing, mengisi baris), tetapi tampaknya tidak mungkin. Setidaknya untuk sekarang. Akan menyenangkan untuk mendapatkan kesempatan untuk mengatur posisi awal elemen dengan kata kunci, seperti auto, seolah-olah, mengatakan "Isi baris hingga akhir, mulai dari tepi kiri". Sesuatu seperti ini:

.article {
  grid-column: auto, -1;
}

... yang akan merentangkan rentang di tepi kiri grid ke ujung garis.


All Articles