Tumgik
#NOT ME SAT HERE WRITING THIS FROM A FIREFOX BROWSER............
sporeclan · 2 months
Note
i'm really sad about oakfox dying man but the ash baby crossed my mind for a moment and i'm losing it now
Tumblr media Tumblr media
OAKFOX DIED BRUTALLY BY FIRE AND Y'ALL ARE OUT HERE CALLING HIM A LITTLE BARBECUE BOY ....... CRYING
46 notes · View notes
mlatitlepage776 · 4 years
Video
youtube
Tumblr media
college essays writing
About me
College Essay Writing Service In Usa
College Essay Writing Service In Usa A hardworking pupil whose functions demonstrated my interest in STEM. See how majors and where you’re from can play a part in your utility choices. When you’re nearing the top of your essay, it’s time to put the finishing touches on it with a separate closing paragraph. The conclusion is the place you bring together all the elements you previously talked about in the different sections. No, you don’t have to mention every one explicitly, but your conclusion should cowl most of what you addressed in your essay, and make an excellent clear end to your narrative path. We recommend students ship all their SAT/ACT outcomes to Rutgers. If you already have a SRAR account, created for use with another collaborating college/university, log in along with your SRAR email address and password to complete the linking process for Rutgers. The Self-Reported Academic Record allows college students to self-report their courses, grades, grade-level averages, and different educational information. You ought to fax or mail your waiver request to Rutgers within one week of submitting your admissions software. Earn cash every time a high school person unlocks your full profile. Add your essays, information and advice to help candidates such as you. Varying your word choices retains your copy recent and holds the reader’s attention. Above all, look for phrases or phrases that may be minimize out of your essay to leave just the easiest of what you have to say. Get more data on How to Apply including software and choice dates, admissions profile, entrance necessities, preview the appliance, and the way we make choices. Letters of advice are not used for admissions consideration. The Rutgers utility provides a number of alternatives for candidates to explain their accomplishments, actions, community service, and personal experiences. Students ought to be sure to finish all sections of the Rutgers application to describe themselves. A portfolio, audition, or interview demonstrating artistic talent is required of all Mason Gross School of the Arts applicants. Mason Gross applicants will be emailed a supplemental utility 5 enterprise days after submitting the applying for admission. To study extra about the expertise evaluation necessities and deadlines, visit the school’s Audition and Portfolio Information. The SAT essay and ACT writing part usually are not required. Complete the net utility rigorously because it can't be changed after it has been submitted. You can apply to as many as three Rutgers schools on the one utility and unbiased choices will be made for every school to which you apply. Please notice, older variations of Internet Explorer usually are not supported. If you created an account already, log in using the email address and 8-character password submitted previously. “I never noticed a phenomenal essay all of a sudden make up for every thing” Heaton agreed. We advocate using the most recent versions of EDGE, Google Chrome, or Firefox on your browser when accessing our purposes. To create a Rutgers utility account, present your email address and create an 8-character password. You should create just one pupil account and submit only one software for the yr you plan to enroll. If paying the applying payment would pose a financial hardship and you're currently in high school, see your high school counselor for an official waiver and fax or mail the waiver to us. A $70 non-refundable software fee is required. (Fee information for the School of Health Professions is right here.) Rutgers should receive the payment or a fee waiver before your utility shall be considered full and prepared for review. Rutgers requires that you simply provide a short essay of your original work. Please handle one of the following matters or submit an essay on a subject of your alternative. All the reviews are posted on reputable third party platforms for which we're providing the links to you. You can take a look on the genuine ratings and resolve for yourself whether or not or not you need to have the pleasure of taking essay writing assist from one of the best online essay writing service. I am a perfectionist and due to this fact, I cannot help however writing each essay in the excellent quality and formatting is a should for me. See how AdmitSee compares to different high school application assets.
0 notes
Daily Writing #10 - Take a Break
I sat in the farthest corner of the library, nose in an encyclopedia nearly half my entire body weight, the thick quilt Pinterest made for me over my legs.
Wikipedia had practically shoved me out of my office after I pulled a seventy-hour shift with the order, “Google, go chill for, like, point-five seconds.”
I had begrudgingly complied, and definitely wouldn’t be admitting to them how good it felt now that I was here.
A crash sounded from a few shelves away. I looked up, desperately hoping a lone searcher hadn’t found me.
Instead, Amazon scrambled out of an aisle, knocking books to the ground. His coal-black hair was tousled and slightly sweaty, his steel-blue eyes wild and panicked.
“Hide me!” he cried, sprinting over and crouching at my knees.
I cocked an eyebrow. “From whom?”
“Honey,” Amazon hissed. “She won’t leave me alone!”
“Browser extensions,” I sighed, shaking my head. Chrome could barely wrangle his siblings—Safari, Firefox, and Explorer—let alone his own children.
We both looked up as the library door slammed open out of sight.
“Zee!” a shrill voice called.
Amazon paled. “Please, Google. Help me out.”
I smiled, tapping my chin. “I happen to recall you telling Bing she was the smartest search engine in the Internet. Care to explain?”
His desperate stare went blank for a moment as he frantically searched for some kind of excuse. I’d never experienced such an emotion. Answers were always at my fingertips—whether I wanted them or not.
“I know you’re in here...” Honey sang.
“I’ll buy you waffles,” he said quickly.
“How many?”
He grinned. “As many as you want.”
I rolled my eyes and lifted my feet up onto the table, creating a sort of tent with my quilt. Thankfully, it was long enough to touch the floor. “Get under.”
“Thank you,” he said before disappearing beneath the blanket.
Honey peered around the corner, golden curls bouncing and round, freckled face glowing with excitement.
“Oh, hey, Google,” she chirped, abandoning any sense of mischief. “Have you seen Amazon around here anywhere?”
I felt the tug of an unanswered question behind my teeth. “Yes, I have, but he’s disappeared somewhere.”
“Really? Where’d he go?”
The question tugged again, but my calm expression didn’t falter.
“Somewhere out of sight, I’d imagine. Perhaps you should continue your search.”
“Okay!” she giggled and skipped off.
I returned to my reading, determined to enjoy my brief break no matter who was hidden beneath my blanket.
After several minutes, I said, “Honey is not coming back, Amazon. You could leave with probably chance of success.”
No answer.
Frowning, I peeked under the quilt. Amazon was slumped against a leg of my chair, snoring softly. I smiled. That boy worked himself to death—almost as much as I did—and could often be found asleep on various surfaces around the Internet whenever he could catch a break.
I gave his head a gentle pat, replaced the blanket, and continued reading.
0 notes
emiadegorbon · 7 years
Link
@ptf-and-asm​
Hellow, yez, iz me the anon who asked about fanfiction.
I have news.
FANFICTION. IN BOTH WATTPAD AND TUMBLR.
Chapters will be posted separately with Wattpad links.
It’s the ‘M’s
Firefox sat in her office working diligently – fixing bugs and writing code as always. There was no doubt that there would be a new update before the month was up.
Her door opened and Chrome stuck his head through the door, “Have you checked your email?”
“No,” she replied without looking up at him.
“It’s the ‘M’s.”
Firefox froze and stared at Chrome with wide eyes.
There was a terrifying silence before Chrome pulled his head back, “I’ll tell Internet Explorer!” he shouted as he closed the door.
Firefox quickly went to her email and read the headers of the most recent emails in her inbox:
 Silverlight               Fox, We Talked About This…
Youtube                  WTF jus cuz the web is slow…
Google                    Chrome Won’t Shut Up
M-M                         Attention Browsers!
 She gasped. It was them.
 …
 Firefox burst through Internet Explorer’s office door, nearly shattering it.
“STOP WHAT YOU’RE DOING AND LISTEN TO ME!” she screamed.
Chrome had been shoving news in Chrome’s face while saying something about being better than him as Chrome desperately tried to ward off the browser. However, both stopped to stare bug-eyed at Firefox.
“IE, the ‘M’s are coming to review the new layout and everything needs to look GREAT and I mean GREAT. So that means you need to stay in here until it’s ready. Don’t be slow. I hope your daughter knows what she’s doing because so help us this could mean bonuses or bone-asses!”
Chrome twisted his face, “What?”
“Bone. Asses.”
Internet Explorer raised a finger, “You’re not very good at word-pla…”
“CHROME. Your office needs cleaning ASAP. And whatever you do, do not speak to Google while the ‘M’s are in earshot.”
“But Fox…”
Firefox snatched the news from Chrome’s face and replaced it with her face, “Be fast.”
“Not to worry, Firefox!” Internet Explorer said as he fell into his office chair and nonchalantly stretched out with his hands behind his head, “They’ll love Edge’s work. Her grandfather will make sure of that.”
Firefox placed a protestant hand on her hip, “Her grandfather can’t make him sure of anything. If anything, he might down mark the place specifically because of him.”
“What about Safari?” Chrome said all of a sudden.
They turned to look at him.
“What about Safari?” Firefox raised an eyebrow.
Chrome grinned and crossed his arms, “If Safari likes it, so will…”
“What if Safari doesn’t?” Firefox placed hand on the other hip.
“Then they get extra vacation time so that they do.”
Firefox looked from Chrome to Internet Explorer, “… Alright.”
1 note · View note
therevaliir-blog · 7 years
Text
Announcements: 03-26-2017
Site Changes:
- The Wand (found in Ye Old Sword) has had its description updated.
- Lots up updates to items and their pricings, visit here for the full list and refunds!
- Brittlez has been working tirelessly on a new welcome page that new users will be able to go to as soon as they sign up. This will be separate from the  Starter Kit. She’ll be adding a button to go to the starter kit page from this page as soon as she gets done with this. (She’s  coded most of this herself besides Telly turning it into an html/css page for her) So be gentle! The New Welcome Page This is for new users so they aren't completely lost when they start the site :)
- We discontinued these items:
Goddess Locket- 250 silver. If the owner doesn't own Cure + Heal we will gift them it.
Changling Brooch- 200 + Incognito
Magician's Hat- 300 + Summon Item
Revealing Monocle- 500 + Reveal
Ring of Purity- 150 + Dispel
Heart-Shaped Amulet- 300 + Lucina's Lantern from the Abed Summer Event
Final Breath- 400, was combined with Resurrection there wasn't really a need to have both.
Poison Field- 80, you can literally just cast poison a bunch of times.
Lightning Field- 80, same principal as above.
Dice- 15 
Text Editor:
- The Administration of Revaliir is very, very sorry about the problems with our text editor. Currently, Darros (Telly) is annoyed at all text editors available on the net and he is building his own from the ground up for Rev to use. SO - until that's done we're gonna have to endure the problems this one is giving us. Thank you so much for enduring this terrible problem and we assure you that… THAT IS NOT SCREAMS OF BLOODY MURDER!!!! that you hear in the backend of Rev. (ok it is we're murdering the text editor). But we're trying to get this fixed as soon as possible. Code just takes a long time to write and make sure it works with our current set up. <3
-   Anyone who has problems with their posts get ahold of me. Everyone pasting from ANYWHERE even here highlight your post hit the remove format button. Then bit the bbcode button to see your paragraphs disappear. THEN reinsert all of your paragraphs and put in your bbcode. I understand this is a pain but this is a temporary solution until we roll back the old text editor. I've been pulling my hair out trying to figure out why some browsers are having it worse than others.
Firefox + Google Docs = Blank space
Firefox + Word Doc/Libre = Aligning left for some weird reason
Chrome + both = removal of all paragraphs (this is the least worrisome out of all of it)
I don't know about edge though because I refuse to touch it :V
-  Darros edited the code on the text editor.  It should strip the formatting on paste now.
Two New Gods Announced!:
We debated for a good hour or more and only two choices remained when we were done. Before we go on to announce the chosen for these spots we decided to go into a bit about choosing them. First: We didn’t choose them out of favoritism. Each has the skills we look for. One of them we shot down multiple times and told them to keep applying and how they could improve. Second: We wanted you to make sure that you knew that *I* wasn’t biased in this. You’ll understand when I get to the results. I was most critical of both of our choices and tore them apart worse than the other two Triune members. If anything these choices had it worse than the other applicants making the scales tip in the other applicants' favors. Now we get on to the god selection: Our new gods are: Porthyrius, the Keeper of the Keys and Secrets of Knowledge and the Arcane, The One with the Silvered Tongue.   Xunatar,  the Chaosweaver and the Lord of Lies. Gypsy(Porthyrius), does an enormous amount of things for Revaliir behind the scenes. She not only draws for us but she has come up with many ideas for the site that we’ve implemented. Every project we’ve ever started she’s joined. Her activity level is second to none (Well maybe myself). She is friendly and helpful to all who come to her. We were worried about announcing Gypsy as well but we believe that her activity and devotion to the site speaks for itself. Brandon(Xunatar), is a moderator on our site. He has been with Revaliir since the June before we opened our doors. He was/is some of the driving force for things we do. He helps all and will rp with anyone. He is the ideal Moderator but we weren’t looking for a moderator when we chose him for this spot. His lore weaving is some of the best I’ve seen(That we have seen). He also have a high activity count, which we count. He can also rp with anyone easily. This is not the first time he’s applied but he has worked on the things we told him too. We’re glad to have him not only as our moderator but as what we hope to be a long standing deity. When selecting him I sat in a different room and he didn’t know a thing about what I was doing. He didn’t know and still doesn’t know that we picked him. This will be the first he’s heard of it despite us living together. Brandon’s selection is the hardest because we worried people would think I was being biased. However, I am only one person out of three and easily out voted. The others saw what I did. An evolving roleplayer who has earned his right to become a deity ontop of his job as moderator. He has an even harder job as I’ll be over him making sure that he gets his stuff done. By no means does he have this easy, if anything he has it harder. I don’t like our deities slacking no matter who they are. Revaliir is our baby and we wouldn’t put any ol person as a deity just because we like them as a person. Overall I owed this explanation to no one. As I hoped that you all would trust in my judgment and trust me to be fair. I’m doing this because I want to be transparent with everyone. Cello and Whitney agreed with that line of thought and we thought this was best. That being said anyone who gets caught ranting to members in the discord or on skype (anywhere it gets reported from) will be issued a warning. We’ve had problems in the past with people thinking we promote favoritism. We don’t. I certainly do not. As I said before those I choose are what I believe to be the ideal person for roleplaying and being an active leader in our community. That’s all I want for this site. However, their applications have to make sense and I won’t sit with rose-colored glasses. I’ve ripped apart their applications down to the single most elusive detail. All in all these two have earned their spots and I’ll be happy to talk to whoever didn’t get the spots and help them with their applications if they want for the future (keep in mind the applications might change for the next round whenever we have them). Brandon’s moderator position will be moved to Xunatar following this announcement. This rounds out the conclave to 6. Unless we see a higher number of people on the site or someone falls this will be the last god selection for a while. Also this interestingly enough rounds out the conclave: 2 good, 2 neutral, and 2 evil.
Just a Reminder:
Rev is getting a whole bunch of new people! We understand everyone is excited but we would like to remind people that they need to read the rules. Revaliir is a high fantasy medieval site with its own lore. We don't go by the real world here nor do we necessarily go by the written lore of others. 1. Only Gods can be Immortal: Lemme explain. There is no rule on age here in Revaliir. We're not talking about THAT kind of immortal. We're talking about being able to take hellfire from another God and living. We're talking about taking so much damage that your body is barely being held together. THAT kind of immortal. That is why Immortal is only reserved for the gods. No mortal(aka not gods) should be able to take that kind of damage and live without an outside source.(say a God healing you) Not dying from illness? Have cure on you. It's a cheap spell. Don't die from poisons (not godly poisons looking at you Dal) but regular poisons? Get cure again. Heck you can't even be killed unless you give permission so your character is practically immortal anyways as long as you don't powerplay. 2. You have to rp with the items in your inventory. We have shops and silver for a reason. This puts everyone on equal footing. Everyone starts off the same. Even the original staff members of the site started out with nothing but their starter packs. That being said your stories don't have to be the same. 3.We are not restricting you. I've been to plenty of rp sites where you can't play whatever you want. We're literally restricting you on one thing, Immortality. The items thing? That isn't a big deal. If you rp a lot and advertise (you get the x3 silver boost for that) you'll have the items you need in no time at all. 4. No one is allowed to have demi-god characters. Don't even Gods can spawn Demi-gods. This makes all characters not gods equal. 5. Even the Triune is equal to the Gods. We get no extra power but the ability to call mandatory conclaves. 6. We restricted our Gods outside of temples to make it more fair for everyone.  Hense the 3 god rules. Past those 3 rules we can't do anything to you without your permission. We can't even kill your characters even in our temples. (because that is fair) You guys have free reign to do whatever you want on Rev as long as it's within the rules. You can have your own kingdom. You can have your own guild. You can do whatever your heart desires within the rules. We don't even have that many restrictions on things like that. We aren't being cruel or unfair by setting rules and guidelines. If you have a problem with it talk to an administrator or try and understand why we have it the way we do. Revaliir is one of the most free-form rp sites out there with its own lore. We truly can't help you if you think Rev isn't for you and we also hope you don't expect us to change Revaliir for you. Do not under ANY circumstances insult Rev staff or userbase because you don't get your way. We're all mature adults/blossoming young adults. If you have problems with stuff get ahold of staff. If you think you need something for character building so you can start get ahold of me. I have 10,000 silver I will gladly help you. There is no excuse for not following the rules, being rude to staff members who are doing their jobs, or screaming we're unfair. You being that way makes it unfair to everyone who are following the guidelines and rules. We will do whatever it takes so that our regular everyday users have peace of mind. This is by no means calling ANYONE out. It has happened one too many times and I will start being the one who handles it if this keeps up. You don't want that and I don't either. I quite like being the bubbly lead administration besides the other two who are regularly in charge of being the mean ones(sorry gals I love you). However, I won't watch our staff or userbase be treated like that. I assure you that I am 10x as worse as the others when warranted so please don't make me be that way because I don't want to be. I want to see Rev grow and become better and also not have a toxic community. Now please everyone get along and be understanding to each other! (Also read up the rules. I posted the Welcome page up that would be a good place to start) Also please remember that most of us do this after a long day's work or in between children needing their parents. This is our fun time too. Sorry for being mean, Brittlez One of the Lead Site Administrators One of the Lead Site Administrators
Staff Breakdown:
In order to better serve the user base of the site, here is the actual breakdown of personnel to seek out when a problem arrives. Please make sure that you seek out the appropriate staff members; if not then the problem will be forwarded to the correct parties. Moderators (Green Usernames): For post related problems, issues with harassment from another non staff member, general questions about the site. Administrators (Blue Usernames): For moving actual threads to their proper locations, activating accounts, moving items, issues with the shop, resetting passwords, distributing silver, having issues with warnings and strikes, having issues with moderators. Triune(Golden Usernames): Custom item creation (Angela Rose), issues with another Triune member, issues with an Administrator, event related problems, issues with Deity members, general questions about Deities and lore. *Angela Rose and Dalenesca may be contacted if no Admin is currently online at the time of needed assistance and either of them are.*
News, Updates, and Revivals:
We've added some new stuff to the site to help people out… and we've updated some old stuff/revived it to check to see if there is any interest. 1. Synth Recommendations + Other Info : This has a list of pricing for trades. Info on a bunch of other stuff like custom items, event items, etc, etc. For more info go read it real quick :) 2. Wish Upon a Star : A weekly Synth Ingredient Lottery that will roll every Saturday has been started. Zanetimm92 is my faithful helper. Read up on the rules about it to get started. 3. The Wishing Well : Rules have been updated to include synth ingredients and synth items. 4. Roleplay Roulette : Has been restarted and I am gauging interest on whether or not to keep it stickied. It was previously left alone due to not only activity but Revaliir getting busy. This is a fun way to get a new/old roleplay partner. Read up on the rules!
0 notes
aaronbarrnna · 7 years
Text
Practical CSS Grid: Adding Grid to an Existing Design
Understanding and using Grid is easier than you might expect. The day Grid support shipped in Firefox 52, I decided on the spur of the moment to convert the basic layout of my personal site to use Grid. And it was a fairly simple process—five minutes to write the grid styles, then 15-20 spent troubleshooting.
Grid allows us to literally define column and row grid lines, then attach elements to those lines in any order we choose. That may sound like tables, but Grid is so much more than tables ever dreamed. It means more responsive layouts, far more accessible documents, and far clearer markup than even floats and positioning ever afforded us.
It’s been decades since CSS first emerged, but it’s never contained a system anything like this. And Grid is already supported in both Chrome and Firefox, with Safari coming soon (its Technology Preview releases support Grid). A new era in digital design is dawning right now.
The way things used to be
Before we get to the Grid, allow me to take just a moment to explain the markup structure of meyerweb’s main pages, and the positioning-and-margins approach I’ve been using for, um, about 12 years now. Here’s how the markup is structured:
<body> <div id="sitemast">…</div> <div id="search">…</div> <div id="main">…</div> <div id="extra">…</div> <div id="navigate">…</div> <div id="footer">…</div> </body>
Some of the names are indiosyncratic holdovers from my early-2000s view of layout and naming conventions. #extra, for example, is what most of us would call #sidebar. #sitemast stands in for #masthead. And #footer is from the days before the actual <footer> element.
The divs (which should probably be sections these days, but never mind that now) are arranged the way they are so that if the CSS fails to load, or a speaking browser is used to browse the site, then the site’s masthead is first, the ability to search the site is second, and the main content of the page is third. After that, extra materials, site navigation, and the footer follow.
All of these were stitched together into a layout by absolutely positioning the navigate and search divs. The sitemast was set to be 192px tall, and both the navigate and search divs were given top: 192px; to show up just below it. In order to leave space for them to land, top margins were applied to the main and extra divs. (Fig. 1)
Fig. 1: meyerweb’s home page (foreshortened)  Constructing the grid
So that’s how things have been laid out since the middle of 2005, more or less. I fiddled with a flexbox layout at one point as an experiment, but never shipped it, because it felt clumsy to be using a one-dimensional layout tool to manage a two-dimensional layout. I probably should have converted the navigation bar to flexbox, but I got distracted by something else and never returned to the effort.
Besides, Grid was coming. In the run-up to Grid shipping in Firefox 52, I was focused on learning and teaching Grid, creating test cases, and using it to build figures for publication. And then, March 7th, 2017, it shipped to the public in Firefox 52. I tweeted and posted an article and demo I’d put together the night before, and sat back in wonderment that the day had finally come to pass. After 20+ years of CSS, finally, a real layout system, a set of properties and values designed from the outset for that purpose.
And then I decided, more or less in that moment, to convert my personal site to use Grid for its main-level layout. It took me less than five minutes to come up with the following:
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
That’s not all I had to do, but it’s the core. Let me break it down for you.
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; }
This part sets the body element to be a grid container and sets up the grid lines. When you make an element a grid container, all of its children become grid items. (If you’ve worked with flexbox, then this pattern will be familiar to you.) So with that display: grid, I turned all of the child divs into grid items.
Next come the rows in the grid. The values in grid-template-rows actually define separation distances between grid lines (the same is true of grid-template-columns, which we’ll get to in a moment). So the value 192px min-content min-content 1fr; means: “Go 192 pixels down from the top of the grid container and drop a grid line. Then drop another two such that they provide enough vertical space for the contents of the rows they define. Finally, leave one fr (fraction) of distance between the third grid line and the bottom of the grid container.” (Fig. 2)
Fig. 2: Defining the rows 
The value min-content is pretty cool. It means just what it says: “Take up the minimum amount of space needed to fit the contents.” So for the second row, the one that will contain the navigation bar and search field, it will be as tall as the taller of the two, and no taller.
Ditto for the third row, the one containing the main and extra divs. On the homepage, the main div will be taller. On subpages, that might not always be the case. In all circumstances, the row containing those two divs will always be tall enough to contain them both.
With the rows figured out, next come the columns. I decided to keep things simple and just set up two. If you look at meyerweb’s home page, it appears to have three columns, but that’s only true of blog posts—a substantial but minority part of the site—and the left-side “column” is more of a sidebar inside the main column.
In the original design, the sidebar (#extra) is 18em wide, with some extra space to keep it away from the main column. But the column also has to fit the search box, which is a bit wider. After some experimentation, I settled on a width of 20em. The rest was left to flex as 1fr. (Fig. 3)
Fig. 3: Defining the columns 
Now that I’ve used the fr unit twice, a few words of explanation are in order. fr stands for “fraction,” and means “a fraction of the available unconstrained space.” With the columns, there are two columns. One of them has an explicit width of 20em, which is thus constrained—there’s no room for flexibility. The rest of the column space is unconstrained—as the width of the grid container changes (say, due to changes of the browser window) the unconstrained space will change to be the container’s width minus the 20em of constrained space.
Imagine for a moment I’d decided to split the grid into four columns, with the rightmost being 20em wide and the rest being equal, flexible widths. That would have looked like:
grid-template-columns: 1fr 1fr 1fr 20em;
Alternatively, I could have written it as:
grid-template-columns: repeat(3, 1fr) 20em;
In any event, that would have caused the unconstrained space to be divided equally among the first three columns. If the grid container were 65em wide, the last column would be 20em wide, and the other three 15em each. (3 x 15 = 45; 45 + 20 = 65.) Shrink the grid container down 50em wide, and the first three columns would shrink to 10em each.
In my case, I wanted that first column to take all of the space not given to the constrained last column, so it got 1fr. The final result is shown in Fig. 4.
Fig. 4: The complete grid  Placing the items
With the grid lines set up, now it’s just a matter of attached the grid items to the grid lines. This happens automatically, using the grid-flow algorithm, but this is case where I want to place each thing in a specific place. That leads to the following:
#sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
For each of the six divs, I just said, “Pin your top to this row line, and your left to this column line.” I used line numbers because that’s all I gave myself. It’s possible to assign names to grid lines, but I didn’t. (But stay tuned for an example of this, later in the article!)
So, as an example, I set up the #main portion to start on the third row line and the first column line. That means it will, by default, fill out the space from the first to second column lines, and from the third to fourth row lines.
Almost all of the divs were set up in this way. The exception in this case is the @sitemast. It starts at the first column and row lines, but since I wanted it to go all the way across the grid, I set its column value to 1 / span 2. That means “Start at column line 1, and span across two columns.” I could have gotten the same result with the value 1 / 3, which means “Go from column line 1 to column line 3.” (Fig. 5)
Fig. 5: The grid items’ placement 
But realize: that’s just a diagram, not the actual layout situation. Not yet, at any rate. Something I want to be clear about here is that while you can explicitly assign all of your grid items to specific rows and columns, you don’t have to do so. Grid has a flow model that allows grid items to be automatically assigned to the next open grid cell, depending on the flow direction. In my case, I could have gotten away with only these rules:
#sitemast { grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; }
That would have ensured the masthead was two columns wide, and that the search and navigation divs were placed in the exact grid cells I wanted. That would have left the second row filled by navigation and search, and the rest of the grid cells open.
Given that, the unassigned items would be flowed into the grid in source order. The masthead would be placed in the first two-column row it could find, which turns out to be the first. Then the main div would flow into the first open cell: row 3, column 1. Extra would go into the next cell: row 3, column 2. And then the footer would be placed into row 4, column 1.
The end result would be exactly what’s shown in Fig. 5. The difference would be that if I had a special page where another div was added, it could throw off the whole layout, depending on where it appeared in the HTML. By explicitly assigning my layout pieces to the places I want them, I prevent a stray element upending everything.
Of course, if a child element of the body is added to a page, it will become a grid item. If I don’t give it a place in the grid, it will end up flowed into the first available grid cell. Since the lower-right cell (row 4, column 2) is unoccupied, that’s where the extra element would be placed, assuming it isn’t set to span two columns.
Accommodating the past
It’s easy enough to set up a grid, but when you drop grid items into it, they bring all of their existing styles in with them. That might not be a big deal in some cases, but in mine, it meant all of the margins and padding I’d used to keep the layout pieces apart from each other were now messing with the placement of the grid items. You can see this in Fig. 6, created using a local copy of the site.
Fig. 6: Grid + legacy = yoinks 
Ouch. It was time to override the pieces of the legacy layout styles I didn’t need, but of course I needed to keep them for browsers that don’t yet understand Grid.
So I wrapped the whole bit in an @supports block. Since I wanted to constrain the grid layout to wider displays, I put an @media block just inside @supports, and then proceeded to zero out or otherwise change the various margins and padding I didn’t need in a Grid context. Here’s how it turned out:
@supports (display: grid) { @media (min-width: 60.001em) { body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; position: static; padding: 0.25em 0 1em; } #main { grid-row: 3; grid-column: 1; margin-right: 0; margin-top: 1.25em; padding-top: 0; } .hpg #main { margin-top: 0; padding-top: 0; } #extra { grid-row: 3; grid-column: 2; position: static; top: 0; margin-top: 0; padding-top: 0.5em; margin-left: auto; } #navigate { grid-row: 2; grid-column: 1; position: static; margin-top: 1px; padding-bottom: 0; } #footer { grid-row: 4; grid-column: 1; margin-right: 0; } } }
I probably could refactor that to be more efficient, but for now, I’m going to leave it as-is. It makes clear what had to be done to which grid item—which ones needed to override position, which margins and padding needed to be changed, and so on. Let’s look at the end result (Fig. 7).
Fig. 7: Grid + @supports = yowza! 
You might be forgiven for thinking that this was much ado about not very much. Why go to all that effort just to make it look the same? The real power here, in what is admittedly a simple case, is how I no longer have to worry about overlap. The footer will always be below the main and extra divs, no matter which is taller. When I was using positioning, that wasn’t guaranteed.
Similarly, the navigation and search will always maintain a shared height, making sure neither will overlap with the content below them—and thanks to min-content, I don’t have to guess at how tall they might get. Grid just handles all that for me.
And remember, the layout still functions in old browsers just as it always did, using positioning. I didn’t “break” the site for browsers that don’t understand Grid. The more capable Grid layout is there, waiting for browsers like Firefox that understand it.
If you want to see all this live for yourself, head over to meyerweb.com and inspect elements in Firefox 52. There you’ll see a little grid icon next to the display: grid declaration on the body element. Click it, and Firefox will draw the grid lines on the page for you to check out.
Naming conventions
I mentioned earlier that it’s possible to name grid lines. I didn’t do it for my own styles because the grid I defined was so simple, but for more complicated grids, naming the lines might be useful.
Using the stripped-down version of the styles, the one without all the legacy overrides, naming the grid lines would look something like this:
body { display: grid; grid-template-rows: [masthead] 192px [navsearch] min-content [mainextra] min-content [footer] 1fr; grid-template-columns: [left] 1fr [middle] 20em [end]; }
Each of those square-bracketed words is assigned as a name to the corresponding grid line. (Fig. 8)
Fig. 8: Named grid lines 
Once those names are defined, you can refer to them in your grid-row and grid-column properties. For example:
#sitemast { grid-row: masthead; grid-column: left / span right; } #search { grid-row: navsearch; grid-column: middle; } #main { grid-row: mainextra; grid-column: left; } #extra { grid-row: mainextra; grid-column: middle; } #navigate { grid-row: navsearch; grid-column: left; } #footer { grid-row: footer; grid-column: left; }
There’s a lot more possible, too. Much like class names, you can assign multiple names to a grid line by supplying a space-separated list. Try this one for size:
grid-template-columns: [start left] 1fr [middle sidebar] 20em [right end];
You could then refer to any one of those names in your grid-column declaration. There’s no defined limit on the number of names, but remember what comes with great power.
In case you were wondering, you can mix grid line names and numbers, so something like grid-row: navsearch; grid-column: 2; is completely fine. You can use any name the browser can parse, which means you can use just about anything Unicode and your CSS file’s character encoding will handle. And heck, there’s also the very useful grid-area property…but that’s a subject for another day.
Grid and Flexbox
A question you may have is: now that we have Grid, do I throw away flexbox? Absolutely not! The two can and do work very well together.
Consider the navigation bar of my design. For years, it’s been laid out using an unordered list and float: left for the list items. Simplified a bit, the CSS and markup looks like this:
#navlinks { float: left; width: 100%; } #navlinks li { float: left; list-style: none; margin-left: 1px; }
<div id="navigate"> <ul id="navlinks"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li>><a href="…">Speaking</a></li> <li>>><a href="…">Leftovers</a></li> </ul> </div>
Why not display: inline-block instead of float: left? Because that literally wasn’t an option when I wrote the CSS for the navlinks, and I never got around to updating it. (Are you sensing a theme here?)
Now I have two much better options for arranging those links: Grid and Flexbox. I could define a grid there, which would go something like this:
#navlinks { display: grid; grid-template-columns: repeat(6,min-content); } #navlinks li { list-style: none; margin-left: 1px; }
That would essentially get the same result, only in a grid, which is far more robust than either floats or inline blocks. The advantage is that adding new items is easy.
On the other hand, I’d be using Grid, which is a two-dimensional layout system, for a one-dimensional piece of layout. It’s certainly possible to do this, but it feels a little like overkill, and it’s not really what Grid was designed to do. Flexbox, on the other hand, is designed for exactly these kinds of situations.
So I might write the following instead:
#navlinks { display: flex; justify-content: flex-start; flex-wrap: wrap; } #navlinks li { list-style: none; margin-left: 1px; }
Again, that would be basically the same result, but in a more robust fashion. In addition to keeping the links all lined up, the wrap value will let the links go to a second line if need be. And because the flexbox sits inside a grid item that’s part of a grid row whose height is min-content, any increase in height (due to line wrapping or whatever) will cause the entire row to become taller. That means the rows after it will move down to accommodate it.
And now that I look at the markup again, I’ve realized I can simplify that markup without needing to touch any grid styles. Instead of wrapping a list with a div, I can drop the div and reassign its ID to the list. So the markup can become:
<ul id="navigate"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li><a href="…">Speaking</a></li> <li><a href="…">Leftovers</a></li> </ul>
After adjusting the selectors in my CSS from #navlinks to #navigate, the resulting layout will be exactly as it was before. The ul will become a grid item and a flex container. That is a thing you can do.
The downside in my case would be dealing with any interactions between that change and my legacy layout, but it’s not a huge issue to solve. It’s just a matter of doing it.
Letdowns
So what are the down sides?  Not many, but they do exist.
Most fundamentally, there’s no way to define an overall page grid that has all items relate to it. In other words, if I say:
body { display: grid; grid-template-columns: repeat(16, 1fr); }
…then that sets up a 16-column flexible grid for the body element only, and its child elements are the only ones that can become grid items. I can’t reach down into the document tree and assign elements to be placed on that body grid. That’s the main reason I didn’t try to put the little sidebar bits on my blog posts into a shared grid: I literally can’t, at this point, unless I resort to ugly CSS or HTML hackery.
The capability to do such things is known as subgrid, and it hasn’t been implemented by any browsers as yet. There are questions as to exactly how it should or shouldn’t work, so there’s still plenty of hope that everything will work out in the end. It’s a disappointment that we don’t have it yet, and that lack restricts the full range of grid’s power, but hopefully only for a short while.
In the meantime, I’m sure people will come up with ways to work around this limitation. A basic workaround in this case: I could define a grid that applies to every blog post individually, and arrange the pieces of each post on those nested grids. The CSS would look something like:
div.post { display: grid; grid-template-columns: [meta] 10em [main] 1fr; grid-template-rows: [title] min-content [main] 1fr; }
With that, I could place the metadata, the title, and the post’s body text into the defined grid cells, using either grid line numbers or the grid names I set up. Something like:
div.post h3 { grid-column: 2; grid-row: title; } ul.meta { grid-column: meta; grid-row: main; } div.post div.text { grid-column: main; grid-row: main; }
The drawback is that the metadata is then constrained to be a specific width, instead of my being able to set a column that all metadata shares, and size it by the longest bit of content.  That’s no worse than right now, where I’m setting the floated metadata to an explicit width, so this doesn’t lose me anything. It’s just a (temporarily) missed opportunity to gain something.
Another limitation, one that may or may not be addressed, is that you cannot directly style grid cells. Suppose I’d wanted to put a box around the #extra sidebar, completely filling out that cell. I’d have to style the div. I can’t do something like this:
@grid-cell(2, 3) { background: teal; border: 1px solid; }
I mean, I’m not even..
http://ift.tt/2nHTrWF
0 notes
aracecvliwest · 7 years
Text
Practical CSS Grid: Adding Grid to an Existing Design
Understanding and using Grid is easier than you might expect. The day Grid support shipped in Firefox 52, I decided on the spur of the moment to convert the basic layout of my personal site to use Grid. And it was a fairly simple process—five minutes to write the grid styles, then 15-20 spent troubleshooting.
Grid allows us to literally define column and row grid lines, then attach elements to those lines in any order we choose. That may sound like tables, but Grid is so much more than tables ever dreamed. It means more responsive layouts, far more accessible documents, and far clearer markup than even floats and positioning ever afforded us.
It’s been decades since CSS first emerged, but it’s never contained a system anything like this. And Grid is already supported in both Chrome and Firefox, with Safari coming soon (its Technology Preview releases support Grid). A new era in digital design is dawning right now.
The way things used to be
Before we get to the Grid, allow me to take just a moment to explain the markup structure of meyerweb’s main pages, and the positioning-and-margins approach I’ve been using for, um, about 12 years now. Here’s how the markup is structured:
<body> <div id="sitemast">…</div> <div id="search">…</div> <div id="main">…</div> <div id="extra">…</div> <div id="navigate">…</div> <div id="footer">…</div> </body>
Some of the names are indiosyncratic holdovers from my early-2000s view of layout and naming conventions. #extra, for example, is what most of us would call #sidebar. #sitemast stands in for #masthead. And #footer is from the days before the actual <footer> element.
The divs (which should probably be sections these days, but never mind that now) are arranged the way they are so that if the CSS fails to load, or a speaking browser is used to browse the site, then the site’s masthead is first, the ability to search the site is second, and the main content of the page is third. After that, extra materials, site navigation, and the footer follow.
All of these were stitched together into a layout by absolutely positioning the navigate and search divs. The sitemast was set to be 192px tall, and both the navigate and search divs were given top: 192px; to show up just below it. In order to leave space for them to land, top margins were applied to the main and extra divs. (Fig. 1)
Fig. 1: meyerweb’s home page (foreshortened)  Constructing the grid
So that’s how things have been laid out since the middle of 2005, more or less. I fiddled with a flexbox layout at one point as an experiment, but never shipped it, because it felt clumsy to be using a one-dimensional layout tool to manage a two-dimensional layout. I probably should have converted the navigation bar to flexbox, but I got distracted by something else and never returned to the effort.
Besides, Grid was coming. In the run-up to Grid shipping in Firefox 52, I was focused on learning and teaching Grid, creating test cases, and using it to build figures for publication. And then, March 7th, 2017, it shipped to the public in Firefox 52. I tweeted and posted an article and demo I’d put together the night before, and sat back in wonderment that the day had finally come to pass. After 20+ years of CSS, finally, a real layout system, a set of properties and values designed from the outset for that purpose.
And then I decided, more or less in that moment, to convert my personal site to use Grid for its main-level layout. It took me less than five minutes to come up with the following:
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
That’s not all I had to do, but it’s the core. Let me break it down for you.
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; }
This part sets the body element to be a grid container and sets up the grid lines. When you make an element a grid container, all of its children become grid items. (If you’ve worked with flexbox, then this pattern will be familiar to you.) So with that display: grid, I turned all of the child divs into grid items.
Next come the rows in the grid. The values in grid-template-rows actually define separation distances between grid lines (the same is true of grid-template-columns, which we’ll get to in a moment). So the value 192px min-content min-content 1fr; means: “Go 192 pixels down from the top of the grid container and drop a grid line. Then drop another two such that they provide enough vertical space for the contents of the rows they define. Finally, leave one fr (fraction) of distance between the third grid line and the bottom of the grid container.” (Fig. 2)
Fig. 2: Defining the rows 
The value min-content is pretty cool. It means just what it says: “Take up the minimum amount of space needed to fit the contents.” So for the second row, the one that will contain the navigation bar and search field, it will be as tall as the taller of the two, and no taller.
Ditto for the third row, the one containing the main and extra divs. On the homepage, the main div will be taller. On subpages, that might not always be the case. In all circumstances, the row containing those two divs will always be tall enough to contain them both.
With the rows figured out, next come the columns. I decided to keep things simple and just set up two. If you look at meyerweb’s home page, it appears to have three columns, but that’s only true of blog posts—a substantial but minority part of the site—and the left-side “column” is more of a sidebar inside the main column.
In the original design, the sidebar (#extra) is 18em wide, with some extra space to keep it away from the main column. But the column also has to fit the search box, which is a bit wider. After some experimentation, I settled on a width of 20em. The rest was left to flex as 1fr. (Fig. 3)
Fig. 3: Defining the columns 
Now that I’ve used the fr unit twice, a few words of explanation are in order. fr stands for “fraction,” and means “a fraction of the available unconstrained space.” With the columns, there are two columns. One of them has an explicit width of 20em, which is thus constrained—there’s no room for flexibility. The rest of the column space is unconstrained—as the width of the grid container changes (say, due to changes of the browser window) the unconstrained space will change to be the container’s width minus the 20em of constrained space.
Imagine for a moment I’d decided to split the grid into four columns, with the rightmost being 20em wide and the rest being equal, flexible widths. That would have looked like:
grid-template-columns: 1fr 1fr 1fr 20em;
Alternatively, I could have written it as:
grid-template-columns: repeat(3, 1fr) 20em;
In any event, that would have caused the unconstrained space to be divided equally among the first three columns. If the grid container were 65em wide, the last column would be 20em wide, and the other three 15em each. (3 x 15 = 45; 45 + 20 = 65.) Shrink the grid container down 50em wide, and the first three columns would shrink to 10em each.
In my case, I wanted that first column to take all of the space not given to the constrained last column, so it got 1fr. The final result is shown in Fig. 4.
Fig. 4: The complete grid  Placing the items
With the grid lines set up, now it’s just a matter of attached the grid items to the grid lines. This happens automatically, using the grid-flow algorithm, but this is case where I want to place each thing in a specific place. That leads to the following:
#sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
For each of the six divs, I just said, “Pin your top to this row line, and your left to this column line.” I used line numbers because that’s all I gave myself. It’s possible to assign names to grid lines, but I didn’t. (But stay tuned for an example of this, later in the article!)
So, as an example, I set up the #main portion to start on the third row line and the first column line. That means it will, by default, fill out the space from the first to second column lines, and from the third to fourth row lines.
Almost all of the divs were set up in this way. The exception in this case is the @sitemast. It starts at the first column and row lines, but since I wanted it to go all the way across the grid, I set its column value to 1 / span 2. That means “Start at column line 1, and span across two columns.” I could have gotten the same result with the value 1 / 3, which means “Go from column line 1 to column line 3.” (Fig. 5)
Fig. 5: The grid items’ placement 
But realize: that’s just a diagram, not the actual layout situation. Not yet, at any rate. Something I want to be clear about here is that while you can explicitly assign all of your grid items to specific rows and columns, you don’t have to do so. Grid has a flow model that allows grid items to be automatically assigned to the next open grid cell, depending on the flow direction. In my case, I could have gotten away with only these rules:
#sitemast { grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; }
That would have ensured the masthead was two columns wide, and that the search and navigation divs were placed in the exact grid cells I wanted. That would have left the second row filled by navigation and search, and the rest of the grid cells open.
Given that, the unassigned items would be flowed into the grid in source order. The masthead would be placed in the first two-column row it could find, which turns out to be the first. Then the main div would flow into the first open cell: row 3, column 1. Extra would go into the next cell: row 3, column 2. And then the footer would be placed into row 4, column 1.
The end result would be exactly what’s shown in Fig. 5. The difference would be that if I had a special page where another div was added, it could throw off the whole layout, depending on where it appeared in the HTML. By explicitly assigning my layout pieces to the places I want them, I prevent a stray element upending everything.
Of course, if a child element of the body is added to a page, it will become a grid item. If I don’t give it a place in the grid, it will end up flowed into the first available grid cell. Since the lower-right cell (row 4, column 2) is unoccupied, that’s where the extra element would be placed, assuming it isn’t set to span two columns.
Accommodating the past
It’s easy enough to set up a grid, but when you drop grid items into it, they bring all of their existing styles in with them. That might not be a big deal in some cases, but in mine, it meant all of the margins and padding I’d used to keep the layout pieces apart from each other were now messing with the placement of the grid items. You can see this in Fig. 6, created using a local copy of the site.
Fig. 6: Grid + legacy = yoinks 
Ouch. It was time to override the pieces of the legacy layout styles I didn’t need, but of course I needed to keep them for browsers that don’t yet understand Grid.
So I wrapped the whole bit in an @supports block. Since I wanted to constrain the grid layout to wider displays, I put an @media block just inside @supports, and then proceeded to zero out or otherwise change the various margins and padding I didn’t need in a Grid context. Here’s how it turned out:
@supports (display: grid) { @media (min-width: 60.001em) { body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; position: static; padding: 0.25em 0 1em; } #main { grid-row: 3; grid-column: 1; margin-right: 0; margin-top: 1.25em; padding-top: 0; } .hpg #main { margin-top: 0; padding-top: 0; } #extra { grid-row: 3; grid-column: 2; position: static; top: 0; margin-top: 0; padding-top: 0.5em; margin-left: auto; } #navigate { grid-row: 2; grid-column: 1; position: static; margin-top: 1px; padding-bottom: 0; } #footer { grid-row: 4; grid-column: 1; margin-right: 0; } } }
I probably could refactor that to be more efficient, but for now, I’m going to leave it as-is. It makes clear what had to be done to which grid item—which ones needed to override position, which margins and padding needed to be changed, and so on. Let’s look at the end result (Fig. 7).
Fig. 7: Grid + @supports = yowza! 
You might be forgiven for thinking that this was much ado about not very much. Why go to all that effort just to make it look the same? The real power here, in what is admittedly a simple case, is how I no longer have to worry about overlap. The footer will always be below the main and extra divs, no matter which is taller. When I was using positioning, that wasn’t guaranteed.
Similarly, the navigation and search will always maintain a shared height, making sure neither will overlap with the content below them—and thanks to min-content, I don’t have to guess at how tall they might get. Grid just handles all that for me.
And remember, the layout still functions in old browsers just as it always did, using positioning. I didn’t “break” the site for browsers that don’t understand Grid. The more capable Grid layout is there, waiting for browsers like Firefox that understand it.
If you want to see all this live for yourself, head over to meyerweb.com and inspect elements in Firefox 52. There you’ll see a little grid icon next to the display: grid declaration on the body element. Click it, and Firefox will draw the grid lines on the page for you to check out.
Naming conventions
I mentioned earlier that it’s possible to name grid lines. I didn’t do it for my own styles because the grid I defined was so simple, but for more complicated grids, naming the lines might be useful.
Using the stripped-down version of the styles, the one without all the legacy overrides, naming the grid lines would look something like this:
body { display: grid; grid-template-rows: [masthead] 192px [navsearch] min-content [mainextra] min-content [footer] 1fr; grid-template-columns: [left] 1fr [middle] 20em [end]; }
Each of those square-bracketed words is assigned as a name to the corresponding grid line. (Fig. 8)
Fig. 8: Named grid lines 
Once those names are defined, you can refer to them in your grid-row and grid-column properties. For example:
#sitemast { grid-row: masthead; grid-column: left / span right; } #search { grid-row: navsearch; grid-column: middle; } #main { grid-row: mainextra; grid-column: left; } #extra { grid-row: mainextra; grid-column: middle; } #navigate { grid-row: navsearch; grid-column: left; } #footer { grid-row: footer; grid-column: left; }
There’s a lot more possible, too. Much like class names, you can assign multiple names to a grid line by supplying a space-separated list. Try this one for size:
grid-template-columns: [start left] 1fr [middle sidebar] 20em [right end];
You could then refer to any one of those names in your grid-column declaration. There’s no defined limit on the number of names, but remember what comes with great power.
In case you were wondering, you can mix grid line names and numbers, so something like grid-row: navsearch; grid-column: 2; is completely fine. You can use any name the browser can parse, which means you can use just about anything Unicode and your CSS file’s character encoding will handle. And heck, there’s also the very useful grid-area property…but that’s a subject for another day.
Grid and Flexbox
A question you may have is: now that we have Grid, do I throw away flexbox? Absolutely not! The two can and do work very well together.
Consider the navigation bar of my design. For years, it’s been laid out using an unordered list and float: left for the list items. Simplified a bit, the CSS and markup looks like this:
#navlinks { float: left; width: 100%; } #navlinks li { float: left; list-style: none; margin-left: 1px; }
<div id="navigate"> <ul id="navlinks"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li>><a href="…">Speaking</a></li> <li>>><a href="…">Leftovers</a></li> </ul> </div>
Why not display: inline-block instead of float: left? Because that literally wasn’t an option when I wrote the CSS for the navlinks, and I never got around to updating it. (Are you sensing a theme here?)
Now I have two much better options for arranging those links: Grid and Flexbox. I could define a grid there, which would go something like this:
#navlinks { display: grid; grid-template-columns: repeat(6,min-content); } #navlinks li { list-style: none; margin-left: 1px; }
That would essentially get the same result, only in a grid, which is far more robust than either floats or inline blocks. The advantage is that adding new items is easy.
On the other hand, I’d be using Grid, which is a two-dimensional layout system, for a one-dimensional piece of layout. It’s certainly possible to do this, but it feels a little like overkill, and it’s not really what Grid was designed to do. Flexbox, on the other hand, is designed for exactly these kinds of situations.
So I might write the following instead:
#navlinks { display: flex; justify-content: flex-start; flex-wrap: wrap; } #navlinks li { list-style: none; margin-left: 1px; }
Again, that would be basically the same result, but in a more robust fashion. In addition to keeping the links all lined up, the wrap value will let the links go to a second line if need be. And because the flexbox sits inside a grid item that’s part of a grid row whose height is min-content, any increase in height (due to line wrapping or whatever) will cause the entire row to become taller. That means the rows after it will move down to accommodate it.
And now that I look at the markup again, I’ve realized I can simplify that markup without needing to touch any grid styles. Instead of wrapping a list with a div, I can drop the div and reassign its ID to the list. So the markup can become:
<ul id="navigate"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li><a href="…">Speaking</a></li> <li><a href="…">Leftovers</a></li> </ul>
After adjusting the selectors in my CSS from #navlinks to #navigate, the resulting layout will be exactly as it was before. The ul will become a grid item and a flex container. That is a thing you can do.
The downside in my case would be dealing with any interactions between that change and my legacy layout, but it’s not a huge issue to solve. It’s just a matter of doing it.
Letdowns
So what are the down sides?  Not many, but they do exist.
Most fundamentally, there’s no way to define an overall page grid that has all items relate to it. In other words, if I say:
body { display: grid; grid-template-columns: repeat(16, 1fr); }
…then that sets up a 16-column flexible grid for the body element only, and its child elements are the only ones that can become grid items. I can’t reach down into the document tree and assign elements to be placed on that body grid. That’s the main reason I didn’t try to put the little sidebar bits on my blog posts into a shared grid: I literally can’t, at this point, unless I resort to ugly CSS or HTML hackery.
The capability to do such things is known as subgrid, and it hasn’t been implemented by any browsers as yet. There are questions as to exactly how it should or shouldn’t work, so there’s still plenty of hope that everything will work out in the end. It’s a disappointment that we don’t have it yet, and that lack restricts the full range of grid’s power, but hopefully only for a short while.
In the meantime, I’m sure people will come up with ways to work around this limitation. A basic workaround in this case: I could define a grid that applies to every blog post individually, and arrange the pieces of each post on those nested grids. The CSS would look something like:
div.post { display: grid; grid-template-columns: [meta] 10em [main] 1fr; grid-template-rows: [title] min-content [main] 1fr; }
With that, I could place the metadata, the title, and the post’s body text into the defined grid cells, using either grid line numbers or the grid names I set up. Something like:
div.post h3 { grid-column: 2; grid-row: title; } ul.meta { grid-column: meta; grid-row: main; } div.post div.text { grid-column: main; grid-row: main; }
The drawback is that the metadata is then constrained to be a specific width, instead of my being able to set a column that all metadata shares, and size it by the longest bit of content.  That’s no worse than right now, where I’m setting the floated metadata to an explicit width, so this doesn’t lose me anything. It’s just a (temporarily) missed opportunity to gain something.
Another limitation, one that may or may not be addressed, is that you cannot directly style grid cells. Suppose I’d wanted to put a box around the #extra sidebar, completely filling out that cell. I’d have to style the div. I can’t do something like this:
@grid-cell(2, 3) { background: teal; border: 1px solid; }
I mean, I’m not even..
http://ift.tt/2nHTrWF
0 notes
mariaaklnthony · 7 years
Text
Practical CSS Grid: Adding Grid to an Existing Design
Understanding and using Grid is easier than you might expect. The day Grid support shipped in Firefox 52, I decided on the spur of the moment to convert the basic layout of my personal site to use Grid. And it was a fairly simple process—five minutes to write the grid styles, then 15-20 spent troubleshooting.
Grid allows us to literally define column and row grid lines, then attach elements to those lines in any order we choose. That may sound like tables, but Grid is so much more than tables ever dreamed. It means more responsive layouts, far more accessible documents, and far clearer markup than even floats and positioning ever afforded us.
It’s been decades since CSS first emerged, but it’s never contained a system anything like this. And Grid is already supported in both Chrome and Firefox, with Safari coming soon (its Technology Preview releases support Grid). A new era in digital design is dawning right now.
The way things used to be
Before we get to the Grid, allow me to take just a moment to explain the markup structure of meyerweb’s main pages, and the positioning-and-margins approach I’ve been using for, um, about 12 years now. Here’s how the markup is structured:
<body> <div id="sitemast">…</div> <div id="search">…</div> <div id="main">…</div> <div id="extra">…</div> <div id="navigate">…</div> <div id="footer">…</div> </body>
Some of the names are indiosyncratic holdovers from my early-2000s view of layout and naming conventions. #extra, for example, is what most of us would call #sidebar. #sitemast stands in for #masthead. And #footer is from the days before the actual <footer> element.
The divs (which should probably be sections these days, but never mind that now) are arranged the way they are so that if the CSS fails to load, or a speaking browser is used to browse the site, then the site’s masthead is first, the ability to search the site is second, and the main content of the page is third. After that, extra materials, site navigation, and the footer follow.
All of these were stitched together into a layout by absolutely positioning the navigate and search divs. The sitemast was set to be 192px tall, and both the navigate and search divs were given top: 192px; to show up just below it. In order to leave space for them to land, top margins were applied to the main and extra divs. (Fig. 1)
Fig. 1: meyerweb’s home page (foreshortened)  Constructing the grid
So that’s how things have been laid out since the middle of 2005, more or less. I fiddled with a flexbox layout at one point as an experiment, but never shipped it, because it felt clumsy to be using a one-dimensional layout tool to manage a two-dimensional layout. I probably should have converted the navigation bar to flexbox, but I got distracted by something else and never returned to the effort.
Besides, Grid was coming. In the run-up to Grid shipping in Firefox 52, I was focused on learning and teaching Grid, creating test cases, and using it to build figures for publication. And then, March 7th, 2017, it shipped to the public in Firefox 52. I tweeted and posted an article and demo I’d put together the night before, and sat back in wonderment that the day had finally come to pass. After 20+ years of CSS, finally, a real layout system, a set of properties and values designed from the outset for that purpose.
And then I decided, more or less in that moment, to convert my personal site to use Grid for its main-level layout. It took me less than five minutes to come up with the following:
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
That’s not all I had to do, but it’s the core. Let me break it down for you.
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; }
This part sets the body element to be a grid container and sets up the grid lines. When you make an element a grid container, all of its children become grid items. (If you’ve worked with flexbox, then this pattern will be familiar to you.) So with that display: grid, I turned all of the child divs into grid items.
Next come the rows in the grid. The values in grid-template-rows actually define separation distances between grid lines (the same is true of grid-template-columns, which we’ll get to in a moment). So the value 192px min-content min-content 1fr; means: “Go 192 pixels down from the top of the grid container and drop a grid line. Then drop another two such that they provide enough vertical space for the contents of the rows they define. Finally, leave one fr (fraction) of distance between the third grid line and the bottom of the grid container.” (Fig. 2)
Fig. 2: Defining the rows 
The value min-content is pretty cool. It means just what it says: “Take up the minimum amount of space needed to fit the contents.” So for the second row, the one that will contain the navigation bar and search field, it will be as tall as the taller of the two, and no taller.
Ditto for the third row, the one containing the main and extra divs. On the homepage, the main div will be taller. On subpages, that might not always be the case. In all circumstances, the row containing those two divs will always be tall enough to contain them both.
With the rows figured out, next come the columns. I decided to keep things simple and just set up two. If you look at meyerweb’s home page, it appears to have three columns, but that’s only true of blog posts—a substantial but minority part of the site—and the left-side “column” is more of a sidebar inside the main column.
In the original design, the sidebar (#extra) is 18em wide, with some extra space to keep it away from the main column. But the column also has to fit the search box, which is a bit wider. After some experimentation, I settled on a width of 20em. The rest was left to flex as 1fr. (Fig. 3)
Fig. 3: Defining the columns 
Now that I’ve used the fr unit twice, a few words of explanation are in order. fr stands for “fraction,” and means “a fraction of the available unconstrained space.” With the columns, there are two columns. One of them has an explicit width of 20em, which is thus constrained—there’s no room for flexibility. The rest of the column space is unconstrained—as the width of the grid container changes (say, due to changes of the browser window) the unconstrained space will change to be the container’s width minus the 20em of constrained space.
Imagine for a moment I’d decided to split the grid into four columns, with the rightmost being 20em wide and the rest being equal, flexible widths. That would have looked like:
grid-template-columns: 1fr 1fr 1fr 20em;
Alternatively, I could have written it as:
grid-template-columns: repeat(3, 1fr) 20em;
In any event, that would have caused the unconstrained space to be divided equally among the first three columns. If the grid container were 65em wide, the last column would be 20em wide, and the other three 15em each. (3 x 15 = 45; 45 + 20 = 65.) Shrink the grid container down 50em wide, and the first three columns would shrink to 10em each.
In my case, I wanted that first column to take all of the space not given to the constrained last column, so it got 1fr. The final result is shown in Fig. 4.
Fig. 4: The complete grid  Placing the items
With the grid lines set up, now it’s just a matter of attached the grid items to the grid lines. This happens automatically, using the grid-flow algorithm, but this is case where I want to place each thing in a specific place. That leads to the following:
#sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
For each of the six divs, I just said, “Pin your top to this row line, and your left to this column line.” I used line numbers because that’s all I gave myself. It’s possible to assign names to grid lines, but I didn’t. (But stay tuned for an example of this, later in the article!)
So, as an example, I set up the #main portion to start on the third row line and the first column line. That means it will, by default, fill out the space from the first to second column lines, and from the third to fourth row lines.
Almost all of the divs were set up in this way. The exception in this case is the @sitemast. It starts at the first column and row lines, but since I wanted it to go all the way across the grid, I set its column value to 1 / span 2. That means “Start at column line 1, and span across two columns.” I could have gotten the same result with the value 1 / 3, which means “Go from column line 1 to column line 3.” (Fig. 5)
Fig. 5: The grid items’ placement 
But realize: that’s just a diagram, not the actual layout situation. Not yet, at any rate. Something I want to be clear about here is that while you can explicitly assign all of your grid items to specific rows and columns, you don’t have to do so. Grid has a flow model that allows grid items to be automatically assigned to the next open grid cell, depending on the flow direction. In my case, I could have gotten away with only these rules:
#sitemast { grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; }
That would have ensured the masthead was two columns wide, and that the search and navigation divs were placed in the exact grid cells I wanted. That would have left the second row filled by navigation and search, and the rest of the grid cells open.
Given that, the unassigned items would be flowed into the grid in source order. The masthead would be placed in the first two-column row it could find, which turns out to be the first. Then the main div would flow into the first open cell: row 3, column 1. Extra would go into the next cell: row 3, column 2. And then the footer would be placed into row 4, column 1.
The end result would be exactly what’s shown in Fig. 5. The difference would be that if I had a special page where another div was added, it could throw off the whole layout, depending on where it appeared in the HTML. By explicitly assigning my layout pieces to the places I want them, I prevent a stray element upending everything.
Of course, if a child element of the body is added to a page, it will become a grid item. If I don’t give it a place in the grid, it will end up flowed into the first available grid cell. Since the lower-right cell (row 4, column 2) is unoccupied, that’s where the extra element would be placed, assuming it isn’t set to span two columns.
Accommodating the past
It’s easy enough to set up a grid, but when you drop grid items into it, they bring all of their existing styles in with them. That might not be a big deal in some cases, but in mine, it meant all of the margins and padding I’d used to keep the layout pieces apart from each other were now messing with the placement of the grid items. You can see this in Fig. 6, created using a local copy of the site.
Fig. 6: Grid + legacy = yoinks 
Ouch. It was time to override the pieces of the legacy layout styles I didn’t need, but of course I needed to keep them for browsers that don’t yet understand Grid.
So I wrapped the whole bit in an @supports block. Since I wanted to constrain the grid layout to wider displays, I put an @media block just inside @supports, and then proceeded to zero out or otherwise change the various margins and padding I didn’t need in a Grid context. Here’s how it turned out:
@supports (display: grid) { @media (min-width: 60.001em) { body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; position: static; padding: 0.25em 0 1em; } #main { grid-row: 3; grid-column: 1; margin-right: 0; margin-top: 1.25em; padding-top: 0; } .hpg #main { margin-top: 0; padding-top: 0; } #extra { grid-row: 3; grid-column: 2; position: static; top: 0; margin-top: 0; padding-top: 0.5em; margin-left: auto; } #navigate { grid-row: 2; grid-column: 1; position: static; margin-top: 1px; padding-bottom: 0; } #footer { grid-row: 4; grid-column: 1; margin-right: 0; } } }
I probably could refactor that to be more efficient, but for now, I’m going to leave it as-is. It makes clear what had to be done to which grid item—which ones needed to override position, which margins and padding needed to be changed, and so on. Let’s look at the end result (Fig. 7).
Fig. 7: Grid + @supports = yowza! 
You might be forgiven for thinking that this was much ado about not very much. Why go to all that effort just to make it look the same? The real power here, in what is admittedly a simple case, is how I no longer have to worry about overlap. The footer will always be below the main and extra divs, no matter which is taller. When I was using positioning, that wasn’t guaranteed.
Similarly, the navigation and search will always maintain a shared height, making sure neither will overlap with the content below them—and thanks to min-content, I don’t have to guess at how tall they might get. Grid just handles all that for me.
And remember, the layout still functions in old browsers just as it always did, using positioning. I didn’t “break” the site for browsers that don’t understand Grid. The more capable Grid layout is there, waiting for browsers like Firefox that understand it.
If you want to see all this live for yourself, head over to meyerweb.com and inspect elements in Firefox 52. There you’ll see a little grid icon next to the display: grid declaration on the body element. Click it, and Firefox will draw the grid lines on the page for you to check out.
Naming conventions
I mentioned earlier that it’s possible to name grid lines. I didn’t do it for my own styles because the grid I defined was so simple, but for more complicated grids, naming the lines might be useful.
Using the stripped-down version of the styles, the one without all the legacy overrides, naming the grid lines would look something like this:
body { display: grid; grid-template-rows: [masthead] 192px [navsearch] min-content [mainextra] min-content [footer] 1fr; grid-template-columns: [left] 1fr [middle] 20em [end]; }
Each of those square-bracketed words is assigned as a name to the corresponding grid line. (Fig. 8)
Fig. 8: Named grid lines 
Once those names are defined, you can refer to them in your grid-row and grid-column properties. For example:
#sitemast { grid-row: masthead; grid-column: left / span right; } #search { grid-row: navsearch; grid-column: middle; } #main { grid-row: mainextra; grid-column: left; } #extra { grid-row: mainextra; grid-column: middle; } #navigate { grid-row: navsearch; grid-column: left; } #footer { grid-row: footer; grid-column: left; }
There’s a lot more possible, too. Much like class names, you can assign multiple names to a grid line by supplying a space-separated list. Try this one for size:
grid-template-columns: [start left] 1fr [middle sidebar] 20em [right end];
You could then refer to any one of those names in your grid-column declaration. There’s no defined limit on the number of names, but remember what comes with great power.
In case you were wondering, you can mix grid line names and numbers, so something like grid-row: navsearch; grid-column: 2; is completely fine. You can use any name the browser can parse, which means you can use just about anything Unicode and your CSS file’s character encoding will handle. And heck, there’s also the very useful grid-area property…but that’s a subject for another day.
Grid and Flexbox
A question you may have is: now that we have Grid, do I throw away flexbox? Absolutely not! The two can and do work very well together.
Consider the navigation bar of my design. For years, it’s been laid out using an unordered list and float: left for the list items. Simplified a bit, the CSS and markup looks like this:
#navlinks { float: left; width: 100%; } #navlinks li { float: left; list-style: none; margin-left: 1px; }
<div id="navigate"> <ul id="navlinks"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li>><a href="…">Speaking</a></li> <li>>><a href="…">Leftovers</a></li> </ul> </div>
Why not display: inline-block instead of float: left? Because that literally wasn’t an option when I wrote the CSS for the navlinks, and I never got around to updating it. (Are you sensing a theme here?)
Now I have two much better options for arranging those links: Grid and Flexbox. I could define a grid there, which would go something like this:
#navlinks { display: grid; grid-template-columns: repeat(6,min-content); } #navlinks li { list-style: none; margin-left: 1px; }
That would essentially get the same result, only in a grid, which is far more robust than either floats or inline blocks. The advantage is that adding new items is easy.
On the other hand, I’d be using Grid, which is a two-dimensional layout system, for a one-dimensional piece of layout. It’s certainly possible to do this, but it feels a little like overkill, and it’s not really what Grid was designed to do. Flexbox, on the other hand, is designed for exactly these kinds of situations.
So I might write the following instead:
#navlinks { display: flex; justify-content: flex-start; flex-wrap: wrap; } #navlinks li { list-style: none; margin-left: 1px; }
Again, that would be basically the same result, but in a more robust fashion. In addition to keeping the links all lined up, the wrap value will let the links go to a second line if need be. And because the flexbox sits inside a grid item that’s part of a grid row whose height is min-content, any increase in height (due to line wrapping or whatever) will cause the entire row to become taller. That means the rows after it will move down to accommodate it.
And now that I look at the markup again, I’ve realized I can simplify that markup without needing to touch any grid styles. Instead of wrapping a list with a div, I can drop the div and reassign its ID to the list. So the markup can become:
<ul id="navigate"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li><a href="…">Speaking</a></li> <li><a href="…">Leftovers</a></li> </ul>
After adjusting the selectors in my CSS from #navlinks to #navigate, the resulting layout will be exactly as it was before. The ul will become a grid item and a flex container. That is a thing you can do.
The downside in my case would be dealing with any interactions between that change and my legacy layout, but it’s not a huge issue to solve. It’s just a matter of doing it.
Letdowns
So what are the down sides?  Not many, but they do exist.
Most fundamentally, there’s no way to define an overall page grid that has all items relate to it. In other words, if I say:
body { display: grid; grid-template-columns: repeat(16, 1fr); }
…then that sets up a 16-column flexible grid for the body element only, and its child elements are the only ones that can become grid items. I can’t reach down into the document tree and assign elements to be placed on that body grid. That’s the main reason I didn’t try to put the little sidebar bits on my blog posts into a shared grid: I literally can’t, at this point, unless I resort to ugly CSS or HTML hackery.
The capability to do such things is known as subgrid, and it hasn’t been implemented by any browsers as yet. There are questions as to exactly how it should or shouldn’t work, so there’s still plenty of hope that everything will work out in the end. It’s a disappointment that we don’t have it yet, and that lack restricts the full range of grid’s power, but hopefully only for a short while.
In the meantime, I’m sure people will come up with ways to work around this limitation. A basic workaround in this case: I could define a grid that applies to every blog post individually, and arrange the pieces of each post on those nested grids. The CSS would look something like:
div.post { display: grid; grid-template-columns: [meta] 10em [main] 1fr; grid-template-rows: [title] min-content [main] 1fr; }
With that, I could place the metadata, the title, and the post’s body text into the defined grid cells, using either grid line numbers or the grid names I set up. Something like:
div.post h3 { grid-column: 2; grid-row: title; } ul.meta { grid-column: meta; grid-row: main; } div.post div.text { grid-column: main; grid-row: main; }
The drawback is that the metadata is then constrained to be a specific width, instead of my being able to set a column that all metadata shares, and size it by the longest bit of content.  That’s no worse than right now, where I’m setting the floated metadata to an explicit width, so this doesn’t lose me anything. It’s just a (temporarily) missed opportunity to gain something.
Another limitation, one that may or may not be addressed, is that you cannot directly style grid cells. Suppose I’d wanted to put a box around the #extra sidebar, completely filling out that cell. I’d have to style the div. I can’t do something like this:
@grid-cell(2, 3) { background: teal; border: 1px solid; }
I mean, I’m not even..
http://ift.tt/2nHTrWF
0 notes
joannlyfgnch · 7 years
Text
Practical CSS Grid: Adding Grid to an Existing Design
Understanding and using Grid is easier than you might expect. The day Grid support shipped in Firefox 52, I decided on the spur of the moment to convert the basic layout of my personal site to use Grid. And it was a fairly simple process—five minutes to write the grid styles, then 15-20 spent troubleshooting.
Grid allows us to literally define column and row grid lines, then attach elements to those lines in any order we choose. That may sound like tables, but Grid is so much more than tables ever dreamed. It means more responsive layouts, far more accessible documents, and far clearer markup than even floats and positioning ever afforded us.
It’s been decades since CSS first emerged, but it’s never contained a system anything like this. And Grid is already supported in both Chrome and Firefox, with Safari coming soon (its Technology Preview releases support Grid). A new era in digital design is dawning right now.
The way things used to be
Before we get to the Grid, allow me to take just a moment to explain the markup structure of meyerweb’s main pages, and the positioning-and-margins approach I’ve been using for, um, about 12 years now. Here’s how the markup is structured:
<body> <div id="sitemast">…</div> <div id="search">…</div> <div id="main">…</div> <div id="extra">…</div> <div id="navigate">…</div> <div id="footer">…</div> </body>
Some of the names are indiosyncratic holdovers from my early-2000s view of layout and naming conventions. #extra, for example, is what most of us would call #sidebar. #sitemast stands in for #masthead. And #footer is from the days before the actual <footer> element.
The divs (which should probably be sections these days, but never mind that now) are arranged the way they are so that if the CSS fails to load, or a speaking browser is used to browse the site, then the site’s masthead is first, the ability to search the site is second, and the main content of the page is third. After that, extra materials, site navigation, and the footer follow.
All of these were stitched together into a layout by absolutely positioning the navigate and search divs. The sitemast was set to be 192px tall, and both the navigate and search divs were given top: 192px; to show up just below it. In order to leave space for them to land, top margins were applied to the main and extra divs. (Fig. 1)
Fig. 1: meyerweb’s home page (foreshortened)  Constructing the grid
So that’s how things have been laid out since the middle of 2005, more or less. I fiddled with a flexbox layout at one point as an experiment, but never shipped it, because it felt clumsy to be using a one-dimensional layout tool to manage a two-dimensional layout. I probably should have converted the navigation bar to flexbox, but I got distracted by something else and never returned to the effort.
Besides, Grid was coming. In the run-up to Grid shipping in Firefox 52, I was focused on learning and teaching Grid, creating test cases, and using it to build figures for publication. And then, March 7th, 2017, it shipped to the public in Firefox 52. I tweeted and posted an article and demo I’d put together the night before, and sat back in wonderment that the day had finally come to pass. After 20+ years of CSS, finally, a real layout system, a set of properties and values designed from the outset for that purpose.
And then I decided, more or less in that moment, to convert my personal site to use Grid for its main-level layout. It took me less than five minutes to come up with the following:
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
That’s not all I had to do, but it’s the core. Let me break it down for you.
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; }
This part sets the body element to be a grid container and sets up the grid lines. When you make an element a grid container, all of its children become grid items. (If you’ve worked with flexbox, then this pattern will be familiar to you.) So with that display: grid, I turned all of the child divs into grid items.
Next come the rows in the grid. The values in grid-template-rows actually define separation distances between grid lines (the same is true of grid-template-columns, which we’ll get to in a moment). So the value 192px min-content min-content 1fr; means: “Go 192 pixels down from the top of the grid container and drop a grid line. Then drop another two such that they provide enough vertical space for the contents of the rows they define. Finally, leave one fr (fraction) of distance between the third grid line and the bottom of the grid container.” (Fig. 2)
Fig. 2: Defining the rows 
The value min-content is pretty cool. It means just what it says: “Take up the minimum amount of space needed to fit the contents.” So for the second row, the one that will contain the navigation bar and search field, it will be as tall as the taller of the two, and no taller.
Ditto for the third row, the one containing the main and extra divs. On the homepage, the main div will be taller. On subpages, that might not always be the case. In all circumstances, the row containing those two divs will always be tall enough to contain them both.
With the rows figured out, next come the columns. I decided to keep things simple and just set up two. If you look at meyerweb’s home page, it appears to have three columns, but that’s only true of blog posts—a substantial but minority part of the site—and the left-side “column” is more of a sidebar inside the main column.
In the original design, the sidebar (#extra) is 18em wide, with some extra space to keep it away from the main column. But the column also has to fit the search box, which is a bit wider. After some experimentation, I settled on a width of 20em. The rest was left to flex as 1fr. (Fig. 3)
Fig. 3: Defining the columns 
Now that I’ve used the fr unit twice, a few words of explanation are in order. fr stands for “fraction,” and means “a fraction of the available unconstrained space.” With the columns, there are two columns. One of them has an explicit width of 20em, which is thus constrained—there’s no room for flexibility. The rest of the column space is unconstrained—as the width of the grid container changes (say, due to changes of the browser window) the unconstrained space will change to be the container’s width minus the 20em of constrained space.
Imagine for a moment I’d decided to split the grid into four columns, with the rightmost being 20em wide and the rest being equal, flexible widths. That would have looked like:
grid-template-columns: 1fr 1fr 1fr 20em;
Alternatively, I could have written it as:
grid-template-columns: repeat(3, 1fr) 20em;
In any event, that would have caused the unconstrained space to be divided equally among the first three columns. If the grid container were 65em wide, the last column would be 20em wide, and the other three 15em each. (3 x 15 = 45; 45 + 20 = 65.) Shrink the grid container down 50em wide, and the first three columns would shrink to 10em each.
In my case, I wanted that first column to take all of the space not given to the constrained last column, so it got 1fr. The final result is shown in Fig. 4.
Fig. 4: The complete grid  Placing the items
With the grid lines set up, now it’s just a matter of attached the grid items to the grid lines. This happens automatically, using the grid-flow algorithm, but this is case where I want to place each thing in a specific place. That leads to the following:
#sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
For each of the six divs, I just said, “Pin your top to this row line, and your left to this column line.” I used line numbers because that’s all I gave myself. It’s possible to assign names to grid lines, but I didn’t. (But stay tuned for an example of this, later in the article!)
So, as an example, I set up the #main portion to start on the third row line and the first column line. That means it will, by default, fill out the space from the first to second column lines, and from the third to fourth row lines.
Almost all of the divs were set up in this way. The exception in this case is the @sitemast. It starts at the first column and row lines, but since I wanted it to go all the way across the grid, I set its column value to 1 / span 2. That means “Start at column line 1, and span across two columns.” I could have gotten the same result with the value 1 / 3, which means “Go from column line 1 to column line 3.” (Fig. 5)
Fig. 5: The grid items’ placement 
But realize: that’s just a diagram, not the actual layout situation. Not yet, at any rate. Something I want to be clear about here is that while you can explicitly assign all of your grid items to specific rows and columns, you don’t have to do so. Grid has a flow model that allows grid items to be automatically assigned to the next open grid cell, depending on the flow direction. In my case, I could have gotten away with only these rules:
#sitemast { grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; }
That would have ensured the masthead was two columns wide, and that the search and navigation divs were placed in the exact grid cells I wanted. That would have left the second row filled by navigation and search, and the rest of the grid cells open.
Given that, the unassigned items would be flowed into the grid in source order. The masthead would be placed in the first two-column row it could find, which turns out to be the first. Then the main div would flow into the first open cell: row 3, column 1. Extra would go into the next cell: row 3, column 2. And then the footer would be placed into row 4, column 1.
The end result would be exactly what’s shown in Fig. 5. The difference would be that if I had a special page where another div was added, it could throw off the whole layout, depending on where it appeared in the HTML. By explicitly assigning my layout pieces to the places I want them, I prevent a stray element upending everything.
Of course, if a child element of the body is added to a page, it will become a grid item. If I don’t give it a place in the grid, it will end up flowed into the first available grid cell. Since the lower-right cell (row 4, column 2) is unoccupied, that’s where the extra element would be placed, assuming it isn’t set to span two columns.
Accommodating the past
It’s easy enough to set up a grid, but when you drop grid items into it, they bring all of their existing styles in with them. That might not be a big deal in some cases, but in mine, it meant all of the margins and padding I’d used to keep the layout pieces apart from each other were now messing with the placement of the grid items. You can see this in Fig. 6, created using a local copy of the site.
Fig. 6: Grid + legacy = yoinks 
Ouch. It was time to override the pieces of the legacy layout styles I didn’t need, but of course I needed to keep them for browsers that don’t yet understand Grid.
So I wrapped the whole bit in an @supports block. Since I wanted to constrain the grid layout to wider displays, I put an @media block just inside @supports, and then proceeded to zero out or otherwise change the various margins and padding I didn’t need in a Grid context. Here’s how it turned out:
@supports (display: grid) { @media (min-width: 60.001em) { body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; position: static; padding: 0.25em 0 1em; } #main { grid-row: 3; grid-column: 1; margin-right: 0; margin-top: 1.25em; padding-top: 0; } .hpg #main { margin-top: 0; padding-top: 0; } #extra { grid-row: 3; grid-column: 2; position: static; top: 0; margin-top: 0; padding-top: 0.5em; margin-left: auto; } #navigate { grid-row: 2; grid-column: 1; position: static; margin-top: 1px; padding-bottom: 0; } #footer { grid-row: 4; grid-column: 1; margin-right: 0; } } }
I probably could refactor that to be more efficient, but for now, I’m going to leave it as-is. It makes clear what had to be done to which grid item—which ones needed to override position, which margins and padding needed to be changed, and so on. Let’s look at the end result (Fig. 7).
Fig. 7: Grid + @supports = yowza! 
You might be forgiven for thinking that this was much ado about not very much. Why go to all that effort just to make it look the same? The real power here, in what is admittedly a simple case, is how I no longer have to worry about overlap. The footer will always be below the main and extra divs, no matter which is taller. When I was using positioning, that wasn’t guaranteed.
Similarly, the navigation and search will always maintain a shared height, making sure neither will overlap with the content below them—and thanks to min-content, I don’t have to guess at how tall they might get. Grid just handles all that for me.
And remember, the layout still functions in old browsers just as it always did, using positioning. I didn’t “break” the site for browsers that don’t understand Grid. The more capable Grid layout is there, waiting for browsers like Firefox that understand it.
If you want to see all this live for yourself, head over to meyerweb.com and inspect elements in Firefox 52. There you’ll see a little grid icon next to the display: grid declaration on the body element. Click it, and Firefox will draw the grid lines on the page for you to check out.
Naming conventions
I mentioned earlier that it’s possible to name grid lines. I didn’t do it for my own styles because the grid I defined was so simple, but for more complicated grids, naming the lines might be useful.
Using the stripped-down version of the styles, the one without all the legacy overrides, naming the grid lines would look something like this:
body { display: grid; grid-template-rows: [masthead] 192px [navsearch] min-content [mainextra] min-content [footer] 1fr; grid-template-columns: [left] 1fr [middle] 20em [end]; }
Each of those square-bracketed words is assigned as a name to the corresponding grid line. (Fig. 8)
Fig. 8: Named grid lines 
Once those names are defined, you can refer to them in your grid-row and grid-column properties. For example:
#sitemast { grid-row: masthead; grid-column: left / span right; } #search { grid-row: navsearch; grid-column: middle; } #main { grid-row: mainextra; grid-column: left; } #extra { grid-row: mainextra; grid-column: middle; } #navigate { grid-row: navsearch; grid-column: left; } #footer { grid-row: footer; grid-column: left; }
There’s a lot more possible, too. Much like class names, you can assign multiple names to a grid line by supplying a space-separated list. Try this one for size:
grid-template-columns: [start left] 1fr [middle sidebar] 20em [right end];
You could then refer to any one of those names in your grid-column declaration. There’s no defined limit on the number of names, but remember what comes with great power.
In case you were wondering, you can mix grid line names and numbers, so something like grid-row: navsearch; grid-column: 2; is completely fine. You can use any name the browser can parse, which means you can use just about anything Unicode and your CSS file’s character encoding will handle. And heck, there’s also the very useful grid-area property…but that’s a subject for another day.
Grid and Flexbox
A question you may have is: now that we have Grid, do I throw away flexbox? Absolutely not! The two can and do work very well together.
Consider the navigation bar of my design. For years, it’s been laid out using an unordered list and float: left for the list items. Simplified a bit, the CSS and markup looks like this:
#navlinks { float: left; width: 100%; } #navlinks li { float: left; list-style: none; margin-left: 1px; }
<div id="navigate"> <ul id="navlinks"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li>><a href="…">Speaking</a></li> <li>>><a href="…">Leftovers</a></li> </ul> </div>
Why not display: inline-block instead of float: left? Because that literally wasn’t an option when I wrote the CSS for the navlinks, and I never got around to updating it. (Are you sensing a theme here?)
Now I have two much better options for arranging those links: Grid and Flexbox. I could define a grid there, which would go something like this:
#navlinks { display: grid; grid-template-columns: repeat(6,min-content); } #navlinks li { list-style: none; margin-left: 1px; }
That would essentially get the same result, only in a grid, which is far more robust than either floats or inline blocks. The advantage is that adding new items is easy.
On the other hand, I’d be using Grid, which is a two-dimensional layout system, for a one-dimensional piece of layout. It’s certainly possible to do this, but it feels a little like overkill, and it’s not really what Grid was designed to do. Flexbox, on the other hand, is designed for exactly these kinds of situations.
So I might write the following instead:
#navlinks { display: flex; justify-content: flex-start; flex-wrap: wrap; } #navlinks li { list-style: none; margin-left: 1px; }
Again, that would be basically the same result, but in a more robust fashion. In addition to keeping the links all lined up, the wrap value will let the links go to a second line if need be. And because the flexbox sits inside a grid item that’s part of a grid row whose height is min-content, any increase in height (due to line wrapping or whatever) will cause the entire row to become taller. That means the rows after it will move down to accommodate it.
And now that I look at the markup again, I’ve realized I can simplify that markup without needing to touch any grid styles. Instead of wrapping a list with a div, I can drop the div and reassign its ID to the list. So the markup can become:
<ul id="navigate"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li><a href="…">Speaking</a></li> <li><a href="…">Leftovers</a></li> </ul>
After adjusting the selectors in my CSS from #navlinks to #navigate, the resulting layout will be exactly as it was before. The ul will become a grid item and a flex container. That is a thing you can do.
The downside in my case would be dealing with any interactions between that change and my legacy layout, but it’s not a huge issue to solve. It’s just a matter of doing it.
Letdowns
So what are the down sides?  Not many, but they do exist.
Most fundamentally, there’s no way to define an overall page grid that has all items relate to it. In other words, if I say:
body { display: grid; grid-template-columns: repeat(16, 1fr); }
…then that sets up a 16-column flexible grid for the body element only, and its child elements are the only ones that can become grid items. I can’t reach down into the document tree and assign elements to be placed on that body grid. That’s the main reason I didn’t try to put the little sidebar bits on my blog posts into a shared grid: I literally can’t, at this point, unless I resort to ugly CSS or HTML hackery.
The capability to do such things is known as subgrid, and it hasn’t been implemented by any browsers as yet. There are questions as to exactly how it should or shouldn’t work, so there’s still plenty of hope that everything will work out in the end. It’s a disappointment that we don’t have it yet, and that lack restricts the full range of grid’s power, but hopefully only for a short while.
In the meantime, I’m sure people will come up with ways to work around this limitation. A basic workaround in this case: I could define a grid that applies to every blog post individually, and arrange the pieces of each post on those nested grids. The CSS would look something like:
div.post { display: grid; grid-template-columns: [meta] 10em [main] 1fr; grid-template-rows: [title] min-content [main] 1fr; }
With that, I could place the metadata, the title, and the post’s body text into the defined grid cells, using either grid line numbers or the grid names I set up. Something like:
div.post h3 { grid-column: 2; grid-row: title; } ul.meta { grid-column: meta; grid-row: main; } div.post div.text { grid-column: main; grid-row: main; }
The drawback is that the metadata is then constrained to be a specific width, instead of my being able to set a column that all metadata shares, and size it by the longest bit of content.  That’s no worse than right now, where I’m setting the floated metadata to an explicit width, so this doesn’t lose me anything. It’s just a (temporarily) missed opportunity to gain something.
Another limitation, one that may or may not be addressed, is that you cannot directly style grid cells. Suppose I’d wanted to put a box around the #extra sidebar, completely filling out that cell. I’d have to style the div. I can’t do something like this:
@grid-cell(2, 3) { background: teal; border: 1px solid; }
I mean, I’m not even..
http://ift.tt/2nHTrWF
0 notes
dustinwootenne · 7 years
Text
Practical CSS Grid: Adding Grid to an Existing Design
Understanding and using Grid is easier than you might expect. The day Grid support shipped in Firefox 52, I decided on the spur of the moment to convert the basic layout of my personal site to use Grid. And it was a fairly simple process—five minutes to write the grid styles, then 15-20 spent troubleshooting.
Grid allows us to literally define column and row grid lines, then attach elements to those lines in any order we choose. That may sound like tables, but Grid is so much more than tables ever dreamed. It means more responsive layouts, far more accessible documents, and far clearer markup than even floats and positioning ever afforded us.
It’s been decades since CSS first emerged, but it’s never contained a system anything like this. And Grid is already supported in both Chrome and Firefox, with Safari coming soon (its Technology Preview releases support Grid). A new era in digital design is dawning right now.
The way things used to be
Before we get to the Grid, allow me to take just a moment to explain the markup structure of meyerweb’s main pages, and the positioning-and-margins approach I’ve been using for, um, about 12 years now. Here’s how the markup is structured:
<body> <div id="sitemast">…</div> <div id="search">…</div> <div id="main">…</div> <div id="extra">…</div> <div id="navigate">…</div> <div id="footer">…</div> </body>
Some of the names are indiosyncratic holdovers from my early-2000s view of layout and naming conventions. #extra, for example, is what most of us would call #sidebar. #sitemast stands in for #masthead. And #footer is from the days before the actual <footer> element.
The divs (which should probably be sections these days, but never mind that now) are arranged the way they are so that if the CSS fails to load, or a speaking browser is used to browse the site, then the site’s masthead is first, the ability to search the site is second, and the main content of the page is third. After that, extra materials, site navigation, and the footer follow.
All of these were stitched together into a layout by absolutely positioning the navigate and search divs. The sitemast was set to be 192px tall, and both the navigate and search divs were given top: 192px; to show up just below it. In order to leave space for them to land, top margins were applied to the main and extra divs. (Fig. 1)
Fig. 1: meyerweb’s home page (foreshortened)  Constructing the grid
So that’s how things have been laid out since the middle of 2005, more or less. I fiddled with a flexbox layout at one point as an experiment, but never shipped it, because it felt clumsy to be using a one-dimensional layout tool to manage a two-dimensional layout. I probably should have converted the navigation bar to flexbox, but I got distracted by something else and never returned to the effort.
Besides, Grid was coming. In the run-up to Grid shipping in Firefox 52, I was focused on learning and teaching Grid, creating test cases, and using it to build figures for publication. And then, March 7th, 2017, it shipped to the public in Firefox 52. I tweeted and posted an article and demo I’d put together the night before, and sat back in wonderment that the day had finally come to pass. After 20+ years of CSS, finally, a real layout system, a set of properties and values designed from the outset for that purpose.
And then I decided, more or less in that moment, to convert my personal site to use Grid for its main-level layout. It took me less than five minutes to come up with the following:
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
That’s not all I had to do, but it’s the core. Let me break it down for you.
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; }
This part sets the body element to be a grid container and sets up the grid lines. When you make an element a grid container, all of its children become grid items. (If you’ve worked with flexbox, then this pattern will be familiar to you.) So with that display: grid, I turned all of the child divs into grid items.
Next come the rows in the grid. The values in grid-template-rows actually define separation distances between grid lines (the same is true of grid-template-columns, which we’ll get to in a moment). So the value 192px min-content min-content 1fr; means: “Go 192 pixels down from the top of the grid container and drop a grid line. Then drop another two such that they provide enough vertical space for the contents of the rows they define. Finally, leave one fr (fraction) of distance between the third grid line and the bottom of the grid container.” (Fig. 2)
Fig. 2: Defining the rows 
The value min-content is pretty cool. It means just what it says: “Take up the minimum amount of space needed to fit the contents.” So for the second row, the one that will contain the navigation bar and search field, it will be as tall as the taller of the two, and no taller.
Ditto for the third row, the one containing the main and extra divs. On the homepage, the main div will be taller. On subpages, that might not always be the case. In all circumstances, the row containing those two divs will always be tall enough to contain them both.
With the rows figured out, next come the columns. I decided to keep things simple and just set up two. If you look at meyerweb’s home page, it appears to have three columns, but that’s only true of blog posts—a substantial but minority part of the site—and the left-side “column” is more of a sidebar inside the main column.
In the original design, the sidebar (#extra) is 18em wide, with some extra space to keep it away from the main column. But the column also has to fit the search box, which is a bit wider. After some experimentation, I settled on a width of 20em. The rest was left to flex as 1fr. (Fig. 3)
Fig. 3: Defining the columns 
Now that I’ve used the fr unit twice, a few words of explanation are in order. fr stands for “fraction,” and means “a fraction of the available unconstrained space.” With the columns, there are two columns. One of them has an explicit width of 20em, which is thus constrained—there’s no room for flexibility. The rest of the column space is unconstrained—as the width of the grid container changes (say, due to changes of the browser window) the unconstrained space will change to be the container’s width minus the 20em of constrained space.
Imagine for a moment I’d decided to split the grid into four columns, with the rightmost being 20em wide and the rest being equal, flexible widths. That would have looked like:
grid-template-columns: 1fr 1fr 1fr 20em;
Alternatively, I could have written it as:
grid-template-columns: repeat(3, 1fr) 20em;
In any event, that would have caused the unconstrained space to be divided equally among the first three columns. If the grid container were 65em wide, the last column would be 20em wide, and the other three 15em each. (3 x 15 = 45; 45 + 20 = 65.) Shrink the grid container down 50em wide, and the first three columns would shrink to 10em each.
In my case, I wanted that first column to take all of the space not given to the constrained last column, so it got 1fr. The final result is shown in Fig. 4.
Fig. 4: The complete grid  Placing the items
With the grid lines set up, now it’s just a matter of attached the grid items to the grid lines. This happens automatically, using the grid-flow algorithm, but this is case where I want to place each thing in a specific place. That leads to the following:
#sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
For each of the six divs, I just said, “Pin your top to this row line, and your left to this column line.” I used line numbers because that’s all I gave myself. It’s possible to assign names to grid lines, but I didn’t. (But stay tuned for an example of this, later in the article!)
So, as an example, I set up the #main portion to start on the third row line and the first column line. That means it will, by default, fill out the space from the first to second column lines, and from the third to fourth row lines.
Almost all of the divs were set up in this way. The exception in this case is the @sitemast. It starts at the first column and row lines, but since I wanted it to go all the way across the grid, I set its column value to 1 / span 2. That means “Start at column line 1, and span across two columns.” I could have gotten the same result with the value 1 / 3, which means “Go from column line 1 to column line 3.” (Fig. 5)
Fig. 5: The grid items’ placement 
But realize: that’s just a diagram, not the actual layout situation. Not yet, at any rate. Something I want to be clear about here is that while you can explicitly assign all of your grid items to specific rows and columns, you don’t have to do so. Grid has a flow model that allows grid items to be automatically assigned to the next open grid cell, depending on the flow direction. In my case, I could have gotten away with only these rules:
#sitemast { grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; }
That would have ensured the masthead was two columns wide, and that the search and navigation divs were placed in the exact grid cells I wanted. That would have left the second row filled by navigation and search, and the rest of the grid cells open.
Given that, the unassigned items would be flowed into the grid in source order. The masthead would be placed in the first two-column row it could find, which turns out to be the first. Then the main div would flow into the first open cell: row 3, column 1. Extra would go into the next cell: row 3, column 2. And then the footer would be placed into row 4, column 1.
The end result would be exactly what’s shown in Fig. 5. The difference would be that if I had a special page where another div was added, it could throw off the whole layout, depending on where it appeared in the HTML. By explicitly assigning my layout pieces to the places I want them, I prevent a stray element upending everything.
Of course, if a child element of the body is added to a page, it will become a grid item. If I don’t give it a place in the grid, it will end up flowed into the first available grid cell. Since the lower-right cell (row 4, column 2) is unoccupied, that’s where the extra element would be placed, assuming it isn’t set to span two columns.
Accommodating the past
It’s easy enough to set up a grid, but when you drop grid items into it, they bring all of their existing styles in with them. That might not be a big deal in some cases, but in mine, it meant all of the margins and padding I’d used to keep the layout pieces apart from each other were now messing with the placement of the grid items. You can see this in Fig. 6, created using a local copy of the site.
Fig. 6: Grid + legacy = yoinks 
Ouch. It was time to override the pieces of the legacy layout styles I didn’t need, but of course I needed to keep them for browsers that don’t yet understand Grid.
So I wrapped the whole bit in an @supports block. Since I wanted to constrain the grid layout to wider displays, I put an @media block just inside @supports, and then proceeded to zero out or otherwise change the various margins and padding I didn’t need in a Grid context. Here’s how it turned out:
@supports (display: grid) { @media (min-width: 60.001em) { body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; position: static; padding: 0.25em 0 1em; } #main { grid-row: 3; grid-column: 1; margin-right: 0; margin-top: 1.25em; padding-top: 0; } .hpg #main { margin-top: 0; padding-top: 0; } #extra { grid-row: 3; grid-column: 2; position: static; top: 0; margin-top: 0; padding-top: 0.5em; margin-left: auto; } #navigate { grid-row: 2; grid-column: 1; position: static; margin-top: 1px; padding-bottom: 0; } #footer { grid-row: 4; grid-column: 1; margin-right: 0; } } }
I probably could refactor that to be more efficient, but for now, I’m going to leave it as-is. It makes clear what had to be done to which grid item—which ones needed to override position, which margins and padding needed to be changed, and so on. Let’s look at the end result (Fig. 7).
Fig. 7: Grid + @supports = yowza! 
You might be forgiven for thinking that this was much ado about not very much. Why go to all that effort just to make it look the same? The real power here, in what is admittedly a simple case, is how I no longer have to worry about overlap. The footer will always be below the main and extra divs, no matter which is taller. When I was using positioning, that wasn’t guaranteed.
Similarly, the navigation and search will always maintain a shared height, making sure neither will overlap with the content below them—and thanks to min-content, I don’t have to guess at how tall they might get. Grid just handles all that for me.
And remember, the layout still functions in old browsers just as it always did, using positioning. I didn’t “break” the site for browsers that don’t understand Grid. The more capable Grid layout is there, waiting for browsers like Firefox that understand it.
If you want to see all this live for yourself, head over to meyerweb.com and inspect elements in Firefox 52. There you’ll see a little grid icon next to the display: grid declaration on the body element. Click it, and Firefox will draw the grid lines on the page for you to check out.
Naming conventions
I mentioned earlier that it’s possible to name grid lines. I didn’t do it for my own styles because the grid I defined was so simple, but for more complicated grids, naming the lines might be useful.
Using the stripped-down version of the styles, the one without all the legacy overrides, naming the grid lines would look something like this:
body { display: grid; grid-template-rows: [masthead] 192px [navsearch] min-content [mainextra] min-content [footer] 1fr; grid-template-columns: [left] 1fr [middle] 20em [end]; }
Each of those square-bracketed words is assigned as a name to the corresponding grid line. (Fig. 8)
Fig. 8: Named grid lines 
Once those names are defined, you can refer to them in your grid-row and grid-column properties. For example:
#sitemast { grid-row: masthead; grid-column: left / span right; } #search { grid-row: navsearch; grid-column: middle; } #main { grid-row: mainextra; grid-column: left; } #extra { grid-row: mainextra; grid-column: middle; } #navigate { grid-row: navsearch; grid-column: left; } #footer { grid-row: footer; grid-column: left; }
There’s a lot more possible, too. Much like class names, you can assign multiple names to a grid line by supplying a space-separated list. Try this one for size:
grid-template-columns: [start left] 1fr [middle sidebar] 20em [right end];
You could then refer to any one of those names in your grid-column declaration. There’s no defined limit on the number of names, but remember what comes with great power.
In case you were wondering, you can mix grid line names and numbers, so something like grid-row: navsearch; grid-column: 2; is completely fine. You can use any name the browser can parse, which means you can use just about anything Unicode and your CSS file’s character encoding will handle. And heck, there’s also the very useful grid-area property…but that’s a subject for another day.
Grid and Flexbox
A question you may have is: now that we have Grid, do I throw away flexbox? Absolutely not! The two can and do work very well together.
Consider the navigation bar of my design. For years, it’s been laid out using an unordered list and float: left for the list items. Simplified a bit, the CSS and markup looks like this:
#navlinks { float: left; width: 100%; } #navlinks li { float: left; list-style: none; margin-left: 1px; }
<div id="navigate"> <ul id="navlinks"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li>><a href="…">Speaking</a></li> <li>>><a href="…">Leftovers</a></li> </ul> </div>
Why not display: inline-block instead of float: left? Because that literally wasn’t an option when I wrote the CSS for the navlinks, and I never got around to updating it. (Are you sensing a theme here?)
Now I have two much better options for arranging those links: Grid and Flexbox. I could define a grid there, which would go something like this:
#navlinks { display: grid; grid-template-columns: repeat(6,min-content); } #navlinks li { list-style: none; margin-left: 1px; }
That would essentially get the same result, only in a grid, which is far more robust than either floats or inline blocks. The advantage is that adding new items is easy.
On the other hand, I’d be using Grid, which is a two-dimensional layout system, for a one-dimensional piece of layout. It’s certainly possible to do this, but it feels a little like overkill, and it’s not really what Grid was designed to do. Flexbox, on the other hand, is designed for exactly these kinds of situations.
So I might write the following instead:
#navlinks { display: flex; justify-content: flex-start; flex-wrap: wrap; } #navlinks li { list-style: none; margin-left: 1px; }
Again, that would be basically the same result, but in a more robust fashion. In addition to keeping the links all lined up, the wrap value will let the links go to a second line if need be. And because the flexbox sits inside a grid item that’s part of a grid row whose height is min-content, any increase in height (due to line wrapping or whatever) will cause the entire row to become taller. That means the rows after it will move down to accommodate it.
And now that I look at the markup again, I’ve realized I can simplify that markup without needing to touch any grid styles. Instead of wrapping a list with a div, I can drop the div and reassign its ID to the list. So the markup can become:
<ul id="navigate"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li><a href="…">Speaking</a></li> <li><a href="…">Leftovers</a></li> </ul>
After adjusting the selectors in my CSS from #navlinks to #navigate, the resulting layout will be exactly as it was before. The ul will become a grid item and a flex container. That is a thing you can do.
The downside in my case would be dealing with any interactions between that change and my legacy layout, but it’s not a huge issue to solve. It’s just a matter of doing it.
Letdowns
So what are the down sides?  Not many, but they do exist.
Most fundamentally, there’s no way to define an overall page grid that has all items relate to it. In other words, if I say:
body { display: grid; grid-template-columns: repeat(16, 1fr); }
…then that sets up a 16-column flexible grid for the body element only, and its child elements are the only ones that can become grid items. I can’t reach down into the document tree and assign elements to be placed on that body grid. That’s the main reason I didn’t try to put the little sidebar bits on my blog posts into a shared grid: I literally can’t, at this point, unless I resort to ugly CSS or HTML hackery.
The capability to do such things is known as subgrid, and it hasn’t been implemented by any browsers as yet. There are questions as to exactly how it should or shouldn’t work, so there’s still plenty of hope that everything will work out in the end. It’s a disappointment that we don’t have it yet, and that lack restricts the full range of grid’s power, but hopefully only for a short while.
In the meantime, I’m sure people will come up with ways to work around this limitation. A basic workaround in this case: I could define a grid that applies to every blog post individually, and arrange the pieces of each post on those nested grids. The CSS would look something like:
div.post { display: grid; grid-template-columns: [meta] 10em [main] 1fr; grid-template-rows: [title] min-content [main] 1fr; }
With that, I could place the metadata, the title, and the post’s body text into the defined grid cells, using either grid line numbers or the grid names I set up. Something like:
div.post h3 { grid-column: 2; grid-row: title; } ul.meta { grid-column: meta; grid-row: main; } div.post div.text { grid-column: main; grid-row: main; }
The drawback is that the metadata is then constrained to be a specific width, instead of my being able to set a column that all metadata shares, and size it by the longest bit of content.  That’s no worse than right now, where I’m setting the floated metadata to an explicit width, so this doesn’t lose me anything. It’s just a (temporarily) missed opportunity to gain something.
Another limitation, one that may or may not be addressed, is that you cannot directly style grid cells. Suppose I’d wanted to put a box around the #extra sidebar, completely filling out that cell. I’d have to style the div. I can’t do something like this:
@grid-cell(2, 3) { background: teal; border: 1px solid; }
I mean, I’m not even..
http://ift.tt/2nHTrWF
0 notes
jeanshesallenberger · 7 years
Text
Practical CSS Grid: Adding Grid to an Existing Design
Understanding and using Grid is easier than you might expect. The day Grid support shipped in Firefox 52, I decided on the spur of the moment to convert the basic layout of my personal site to use Grid. And it was a fairly simple process—five minutes to write the grid styles, then 15-20 spent troubleshooting.
Grid allows us to literally define column and row grid lines, then attach elements to those lines in any order we choose. That may sound like tables, but Grid is so much more than tables ever dreamed. It means more responsive layouts, far more accessible documents, and far clearer markup than even floats and positioning ever afforded us.
It’s been decades since CSS first emerged, but it’s never contained a system anything like this. And Grid is already supported in both Chrome and Firefox, with Safari coming soon (its Technology Preview releases support Grid). A new era in digital design is dawning right now.
The way things used to be
Before we get to the Grid, allow me to take just a moment to explain the markup structure of meyerweb’s main pages, and the positioning-and-margins approach I’ve been using for, um, about 12 years now. Here’s how the markup is structured:
<body> <div id="sitemast">…</div> <div id="search">…</div> <div id="main">…</div> <div id="extra">…</div> <div id="navigate">…</div> <div id="footer">…</div> </body>
Some of the names are indiosyncratic holdovers from my early-2000s view of layout and naming conventions. #extra, for example, is what most of us would call #sidebar. #sitemast stands in for #masthead. And #footer is from the days before the actual <footer> element.
The divs (which should probably be sections these days, but never mind that now) are arranged the way they are so that if the CSS fails to load, or a speaking browser is used to browse the site, then the site’s masthead is first, the ability to search the site is second, and the main content of the page is third. After that, extra materials, site navigation, and the footer follow.
All of these were stitched together into a layout by absolutely positioning the navigate and search divs. The sitemast was set to be 192px tall, and both the navigate and search divs were given top: 192px; to show up just below it. In order to leave space for them to land, top margins were applied to the main and extra divs. (Fig. 1)
Fig. 1: meyerweb’s home page (foreshortened)  Constructing the grid
So that’s how things have been laid out since the middle of 2005, more or less. I fiddled with a flexbox layout at one point as an experiment, but never shipped it, because it felt clumsy to be using a one-dimensional layout tool to manage a two-dimensional layout. I probably should have converted the navigation bar to flexbox, but I got distracted by something else and never returned to the effort.
Besides, Grid was coming. In the run-up to Grid shipping in Firefox 52, I was focused on learning and teaching Grid, creating test cases, and using it to build figures for publication. And then, March 7th, 2017, it shipped to the public in Firefox 52. I tweeted and posted an article and demo I’d put together the night before, and sat back in wonderment that the day had finally come to pass. After 20+ years of CSS, finally, a real layout system, a set of properties and values designed from the outset for that purpose.
And then I decided, more or less in that moment, to convert my personal site to use Grid for its main-level layout. It took me less than five minutes to come up with the following:
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
That’s not all I had to do, but it’s the core. Let me break it down for you.
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; }
This part sets the body element to be a grid container and sets up the grid lines. When you make an element a grid container, all of its children become grid items. (If you’ve worked with flexbox, then this pattern will be familiar to you.) So with that display: grid, I turned all of the child divs into grid items.
Next come the rows in the grid. The values in grid-template-rows actually define separation distances between grid lines (the same is true of grid-template-columns, which we’ll get to in a moment). So the value 192px min-content min-content 1fr; means: “Go 192 pixels down from the top of the grid container and drop a grid line. Then drop another two such that they provide enough vertical space for the contents of the rows they define. Finally, leave one fr (fraction) of distance between the third grid line and the bottom of the grid container.” (Fig. 2)
Fig. 2: Defining the rows 
The value min-content is pretty cool. It means just what it says: “Take up the minimum amount of space needed to fit the contents.” So for the second row, the one that will contain the navigation bar and search field, it will be as tall as the taller of the two, and no taller.
Ditto for the third row, the one containing the main and extra divs. On the homepage, the main div will be taller. On subpages, that might not always be the case. In all circumstances, the row containing those two divs will always be tall enough to contain them both.
With the rows figured out, next come the columns. I decided to keep things simple and just set up two. If you look at meyerweb’s home page, it appears to have three columns, but that’s only true of blog posts—a substantial but minority part of the site—and the left-side “column” is more of a sidebar inside the main column.
In the original design, the sidebar (#extra) is 18em wide, with some extra space to keep it away from the main column. But the column also has to fit the search box, which is a bit wider. After some experimentation, I settled on a width of 20em. The rest was left to flex as 1fr. (Fig. 3)
Fig. 3: Defining the columns 
Now that I’ve used the fr unit twice, a few words of explanation are in order. fr stands for “fraction,” and means “a fraction of the available unconstrained space.” With the columns, there are two columns. One of them has an explicit width of 20em, which is thus constrained—there’s no room for flexibility. The rest of the column space is unconstrained—as the width of the grid container changes (say, due to changes of the browser window) the unconstrained space will change to be the container’s width minus the 20em of constrained space.
Imagine for a moment I’d decided to split the grid into four columns, with the rightmost being 20em wide and the rest being equal, flexible widths. That would have looked like:
grid-template-columns: 1fr 1fr 1fr 20em;
Alternatively, I could have written it as:
grid-template-columns: repeat(3, 1fr) 20em;
In any event, that would have caused the unconstrained space to be divided equally among the first three columns. If the grid container were 65em wide, the last column would be 20em wide, and the other three 15em each. (3 x 15 = 45; 45 + 20 = 65.) Shrink the grid container down 50em wide, and the first three columns would shrink to 10em each.
In my case, I wanted that first column to take all of the space not given to the constrained last column, so it got 1fr. The final result is shown in Fig. 4.
Fig. 4: The complete grid  Placing the items
With the grid lines set up, now it’s just a matter of attached the grid items to the grid lines. This happens automatically, using the grid-flow algorithm, but this is case where I want to place each thing in a specific place. That leads to the following:
#sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
For each of the six divs, I just said, “Pin your top to this row line, and your left to this column line.” I used line numbers because that’s all I gave myself. It’s possible to assign names to grid lines, but I didn’t. (But stay tuned for an example of this, later in the article!)
So, as an example, I set up the #main portion to start on the third row line and the first column line. That means it will, by default, fill out the space from the first to second column lines, and from the third to fourth row lines.
Almost all of the divs were set up in this way. The exception in this case is the @sitemast. It starts at the first column and row lines, but since I wanted it to go all the way across the grid, I set its column value to 1 / span 2. That means “Start at column line 1, and span across two columns.” I could have gotten the same result with the value 1 / 3, which means “Go from column line 1 to column line 3.” (Fig. 5)
Fig. 5: The grid items’ placement 
But realize: that’s just a diagram, not the actual layout situation. Not yet, at any rate. Something I want to be clear about here is that while you can explicitly assign all of your grid items to specific rows and columns, you don’t have to do so. Grid has a flow model that allows grid items to be automatically assigned to the next open grid cell, depending on the flow direction. In my case, I could have gotten away with only these rules:
#sitemast { grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; }
That would have ensured the masthead was two columns wide, and that the search and navigation divs were placed in the exact grid cells I wanted. That would have left the second row filled by navigation and search, and the rest of the grid cells open.
Given that, the unassigned items would be flowed into the grid in source order. The masthead would be placed in the first two-column row it could find, which turns out to be the first. Then the main div would flow into the first open cell: row 3, column 1. Extra would go into the next cell: row 3, column 2. And then the footer would be placed into row 4, column 1.
The end result would be exactly what’s shown in Fig. 5. The difference would be that if I had a special page where another div was added, it could throw off the whole layout, depending on where it appeared in the HTML. By explicitly assigning my layout pieces to the places I want them, I prevent a stray element upending everything.
Of course, if a child element of the body is added to a page, it will become a grid item. If I don’t give it a place in the grid, it will end up flowed into the first available grid cell. Since the lower-right cell (row 4, column 2) is unoccupied, that’s where the extra element would be placed, assuming it isn’t set to span two columns.
Accommodating the past
It’s easy enough to set up a grid, but when you drop grid items into it, they bring all of their existing styles in with them. That might not be a big deal in some cases, but in mine, it meant all of the margins and padding I’d used to keep the layout pieces apart from each other were now messing with the placement of the grid items. You can see this in Fig. 6, created using a local copy of the site.
Fig. 6: Grid + legacy = yoinks 
Ouch. It was time to override the pieces of the legacy layout styles I didn’t need, but of course I needed to keep them for browsers that don’t yet understand Grid.
So I wrapped the whole bit in an @supports block. Since I wanted to constrain the grid layout to wider displays, I put an @media block just inside @supports, and then proceeded to zero out or otherwise change the various margins and padding I didn’t need in a Grid context. Here’s how it turned out:
@supports (display: grid) { @media (min-width: 60.001em) { body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; position: static; padding: 0.25em 0 1em; } #main { grid-row: 3; grid-column: 1; margin-right: 0; margin-top: 1.25em; padding-top: 0; } .hpg #main { margin-top: 0; padding-top: 0; } #extra { grid-row: 3; grid-column: 2; position: static; top: 0; margin-top: 0; padding-top: 0.5em; margin-left: auto; } #navigate { grid-row: 2; grid-column: 1; position: static; margin-top: 1px; padding-bottom: 0; } #footer { grid-row: 4; grid-column: 1; margin-right: 0; } } }
I probably could refactor that to be more efficient, but for now, I’m going to leave it as-is. It makes clear what had to be done to which grid item—which ones needed to override position, which margins and padding needed to be changed, and so on. Let’s look at the end result (Fig. 7).
Fig. 7: Grid + @supports = yowza! 
You might be forgiven for thinking that this was much ado about not very much. Why go to all that effort just to make it look the same? The real power here, in what is admittedly a simple case, is how I no longer have to worry about overlap. The footer will always be below the main and extra divs, no matter which is taller. When I was using positioning, that wasn’t guaranteed.
Similarly, the navigation and search will always maintain a shared height, making sure neither will overlap with the content below them—and thanks to min-content, I don’t have to guess at how tall they might get. Grid just handles all that for me.
And remember, the layout still functions in old browsers just as it always did, using positioning. I didn’t “break” the site for browsers that don’t understand Grid. The more capable Grid layout is there, waiting for browsers like Firefox that understand it.
If you want to see all this live for yourself, head over to meyerweb.com and inspect elements in Firefox 52. There you’ll see a little grid icon next to the display: grid declaration on the body element. Click it, and Firefox will draw the grid lines on the page for you to check out.
Naming conventions
I mentioned earlier that it’s possible to name grid lines. I didn’t do it for my own styles because the grid I defined was so simple, but for more complicated grids, naming the lines might be useful.
Using the stripped-down version of the styles, the one without all the legacy overrides, naming the grid lines would look something like this:
body { display: grid; grid-template-rows: [masthead] 192px [navsearch] min-content [mainextra] min-content [footer] 1fr; grid-template-columns: [left] 1fr [middle] 20em [end]; }
Each of those square-bracketed words is assigned as a name to the corresponding grid line. (Fig. 8)
Fig. 8: Named grid lines 
Once those names are defined, you can refer to them in your grid-row and grid-column properties. For example:
#sitemast { grid-row: masthead; grid-column: left / span right; } #search { grid-row: navsearch; grid-column: middle; } #main { grid-row: mainextra; grid-column: left; } #extra { grid-row: mainextra; grid-column: middle; } #navigate { grid-row: navsearch; grid-column: left; } #footer { grid-row: footer; grid-column: left; }
There’s a lot more possible, too. Much like class names, you can assign multiple names to a grid line by supplying a space-separated list. Try this one for size:
grid-template-columns: [start left] 1fr [middle sidebar] 20em [right end];
You could then refer to any one of those names in your grid-column declaration. There’s no defined limit on the number of names, but remember what comes with great power.
In case you were wondering, you can mix grid line names and numbers, so something like grid-row: navsearch; grid-column: 2; is completely fine. You can use any name the browser can parse, which means you can use just about anything Unicode and your CSS file’s character encoding will handle. And heck, there’s also the very useful grid-area property…but that’s a subject for another day.
Grid and Flexbox
A question you may have is: now that we have Grid, do I throw away flexbox? Absolutely not! The two can and do work very well together.
Consider the navigation bar of my design. For years, it’s been laid out using an unordered list and float: left for the list items. Simplified a bit, the CSS and markup looks like this:
#navlinks { float: left; width: 100%; } #navlinks li { float: left; list-style: none; margin-left: 1px; }
<div id="navigate"> <ul id="navlinks"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li>><a href="…">Speaking</a></li> <li>>><a href="…">Leftovers</a></li> </ul> </div>
Why not display: inline-block instead of float: left? Because that literally wasn’t an option when I wrote the CSS for the navlinks, and I never got around to updating it. (Are you sensing a theme here?)
Now I have two much better options for arranging those links: Grid and Flexbox. I could define a grid there, which would go something like this:
#navlinks { display: grid; grid-template-columns: repeat(6,min-content); } #navlinks li { list-style: none; margin-left: 1px; }
That would essentially get the same result, only in a grid, which is far more robust than either floats or inline blocks. The advantage is that adding new items is easy.
On the other hand, I’d be using Grid, which is a two-dimensional layout system, for a one-dimensional piece of layout. It’s certainly possible to do this, but it feels a little like overkill, and it’s not really what Grid was designed to do. Flexbox, on the other hand, is designed for exactly these kinds of situations.
So I might write the following instead:
#navlinks { display: flex; justify-content: flex-start; flex-wrap: wrap; } #navlinks li { list-style: none; margin-left: 1px; }
Again, that would be basically the same result, but in a more robust fashion. In addition to keeping the links all lined up, the wrap value will let the links go to a second line if need be. And because the flexbox sits inside a grid item that’s part of a grid row whose height is min-content, any increase in height (due to line wrapping or whatever) will cause the entire row to become taller. That means the rows after it will move down to accommodate it.
And now that I look at the markup again, I’ve realized I can simplify that markup without needing to touch any grid styles. Instead of wrapping a list with a div, I can drop the div and reassign its ID to the list. So the markup can become:
<ul id="navigate"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li><a href="…">Speaking</a></li> <li><a href="…">Leftovers</a></li> </ul>
After adjusting the selectors in my CSS from #navlinks to #navigate, the resulting layout will be exactly as it was before. The ul will become a grid item and a flex container. That is a thing you can do.
The downside in my case would be dealing with any interactions between that change and my legacy layout, but it’s not a huge issue to solve. It’s just a matter of doing it.
Letdowns
So what are the down sides?  Not many, but they do exist.
Most fundamentally, there’s no way to define an overall page grid that has all items relate to it. In other words, if I say:
body { display: grid; grid-template-columns: repeat(16, 1fr); }
…then that sets up a 16-column flexible grid for the body element only, and its child elements are the only ones that can become grid items. I can’t reach down into the document tree and assign elements to be placed on that body grid. That’s the main reason I didn’t try to put the little sidebar bits on my blog posts into a shared grid: I literally can’t, at this point, unless I resort to ugly CSS or HTML hackery.
The capability to do such things is known as subgrid, and it hasn’t been implemented by any browsers as yet. There are questions as to exactly how it should or shouldn’t work, so there’s still plenty of hope that everything will work out in the end. It’s a disappointment that we don’t have it yet, and that lack restricts the full range of grid’s power, but hopefully only for a short while.
In the meantime, I’m sure people will come up with ways to work around this limitation. A basic workaround in this case: I could define a grid that applies to every blog post individually, and arrange the pieces of each post on those nested grids. The CSS would look something like:
div.post { display: grid; grid-template-columns: [meta] 10em [main] 1fr; grid-template-rows: [title] min-content [main] 1fr; }
With that, I could place the metadata, the title, and the post’s body text into the defined grid cells, using either grid line numbers or the grid names I set up. Something like:
div.post h3 { grid-column: 2; grid-row: title; } ul.meta { grid-column: meta; grid-row: main; } div.post div.text { grid-column: main; grid-row: main; }
The drawback is that the metadata is then constrained to be a specific width, instead of my being able to set a column that all metadata shares, and size it by the longest bit of content.  That’s no worse than right now, where I’m setting the floated metadata to an explicit width, so this doesn’t lose me anything. It’s just a (temporarily) missed opportunity to gain something.
Another limitation, one that may or may not be addressed, is that you cannot directly style grid cells. Suppose I’d wanted to put a box around the #extra sidebar, completely filling out that cell. I’d have to style the div. I can’t do something like this:
@grid-cell(2, 3) { background: teal; border: 1px solid; }
I mean, I’m not even..
http://ift.tt/2nHTrWF
0 notes
waltercostellone · 7 years
Text
Practical CSS Grid: Adding Grid to an Existing Design
Understanding and using Grid is easier than you might expect. The day Grid support shipped in Firefox 52, I decided on the spur of the moment to convert the basic layout of my personal site to use Grid. And it was a fairly simple process—five minutes to write the grid styles, then 15-20 spent troubleshooting.
Grid allows us to literally define column and row grid lines, then attach elements to those lines in any order we choose. That may sound like tables, but Grid is so much more than tables ever dreamed. It means more responsive layouts, far more accessible documents, and far clearer markup than even floats and positioning ever afforded us.
It’s been decades since CSS first emerged, but it’s never contained a system anything like this. And Grid is already supported in both Chrome and Firefox, with Safari coming soon (its Technology Preview releases support Grid). A new era in digital design is dawning right now.
The way things used to be
Before we get to the Grid, allow me to take just a moment to explain the markup structure of meyerweb’s main pages, and the positioning-and-margins approach I’ve been using for, um, about 12 years now. Here’s how the markup is structured:
<body> <div id="sitemast">…</div> <div id="search">…</div> <div id="main">…</div> <div id="extra">…</div> <div id="navigate">…</div> <div id="footer">…</div> </body>
Some of the names are indiosyncratic holdovers from my early-2000s view of layout and naming conventions. #extra, for example, is what most of us would call #sidebar. #sitemast stands in for #masthead. And #footer is from the days before the actual <footer> element.
The divs (which should probably be sections these days, but never mind that now) are arranged the way they are so that if the CSS fails to load, or a speaking browser is used to browse the site, then the site’s masthead is first, the ability to search the site is second, and the main content of the page is third. After that, extra materials, site navigation, and the footer follow.
All of these were stitched together into a layout by absolutely positioning the navigate and search divs. The sitemast was set to be 192px tall, and both the navigate and search divs were given top: 192px; to show up just below it. In order to leave space for them to land, top margins were applied to the main and extra divs. (Fig. 1)
Fig. 1: meyerweb’s home page (foreshortened)  Constructing the grid
So that’s how things have been laid out since the middle of 2005, more or less. I fiddled with a flexbox layout at one point as an experiment, but never shipped it, because it felt clumsy to be using a one-dimensional layout tool to manage a two-dimensional layout. I probably should have converted the navigation bar to flexbox, but I got distracted by something else and never returned to the effort.
Besides, Grid was coming. In the run-up to Grid shipping in Firefox 52, I was focused on learning and teaching Grid, creating test cases, and using it to build figures for publication. And then, March 7th, 2017, it shipped to the public in Firefox 52. I tweeted and posted an article and demo I’d put together the night before, and sat back in wonderment that the day had finally come to pass. After 20+ years of CSS, finally, a real layout system, a set of properties and values designed from the outset for that purpose.
And then I decided, more or less in that moment, to convert my personal site to use Grid for its main-level layout. It took me less than five minutes to come up with the following:
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
That’s not all I had to do, but it’s the core. Let me break it down for you.
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; }
This part sets the body element to be a grid container and sets up the grid lines. When you make an element a grid container, all of its children become grid items. (If you’ve worked with flexbox, then this pattern will be familiar to you.) So with that display: grid, I turned all of the child divs into grid items.
Next come the rows in the grid. The values in grid-template-rows actually define separation distances between grid lines (the same is true of grid-template-columns, which we’ll get to in a moment). So the value 192px min-content min-content 1fr; means: “Go 192 pixels down from the top of the grid container and drop a grid line. Then drop another two such that they provide enough vertical space for the contents of the rows they define. Finally, leave one fr (fraction) of distance between the third grid line and the bottom of the grid container.” (Fig. 2)
Fig. 2: Defining the rows 
The value min-content is pretty cool. It means just what it says: “Take up the minimum amount of space needed to fit the contents.” So for the second row, the one that will contain the navigation bar and search field, it will be as tall as the taller of the two, and no taller.
Ditto for the third row, the one containing the main and extra divs. On the homepage, the main div will be taller. On subpages, that might not always be the case. In all circumstances, the row containing those two divs will always be tall enough to contain them both.
With the rows figured out, next come the columns. I decided to keep things simple and just set up two. If you look at meyerweb’s home page, it appears to have three columns, but that’s only true of blog posts—a substantial but minority part of the site—and the left-side “column” is more of a sidebar inside the main column.
In the original design, the sidebar (#extra) is 18em wide, with some extra space to keep it away from the main column. But the column also has to fit the search box, which is a bit wider. After some experimentation, I settled on a width of 20em. The rest was left to flex as 1fr. (Fig. 3)
Fig. 3: Defining the columns 
Now that I’ve used the fr unit twice, a few words of explanation are in order. fr stands for “fraction,” and means “a fraction of the available unconstrained space.” With the columns, there are two columns. One of them has an explicit width of 20em, which is thus constrained—there’s no room for flexibility. The rest of the column space is unconstrained—as the width of the grid container changes (say, due to changes of the browser window) the unconstrained space will change to be the container’s width minus the 20em of constrained space.
Imagine for a moment I’d decided to split the grid into four columns, with the rightmost being 20em wide and the rest being equal, flexible widths. That would have looked like:
grid-template-columns: 1fr 1fr 1fr 20em;
Alternatively, I could have written it as:
grid-template-columns: repeat(3, 1fr) 20em;
In any event, that would have caused the unconstrained space to be divided equally among the first three columns. If the grid container were 65em wide, the last column would be 20em wide, and the other three 15em each. (3 x 15 = 45; 45 + 20 = 65.) Shrink the grid container down 50em wide, and the first three columns would shrink to 10em each.
In my case, I wanted that first column to take all of the space not given to the constrained last column, so it got 1fr. The final result is shown in Fig. 4.
Fig. 4: The complete grid  Placing the items
With the grid lines set up, now it’s just a matter of attached the grid items to the grid lines. This happens automatically, using the grid-flow algorithm, but this is case where I want to place each thing in a specific place. That leads to the following:
#sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
For each of the six divs, I just said, “Pin your top to this row line, and your left to this column line.” I used line numbers because that’s all I gave myself. It’s possible to assign names to grid lines, but I didn’t. (But stay tuned for an example of this, later in the article!)
So, as an example, I set up the #main portion to start on the third row line and the first column line. That means it will, by default, fill out the space from the first to second column lines, and from the third to fourth row lines.
Almost all of the divs were set up in this way. The exception in this case is the @sitemast. It starts at the first column and row lines, but since I wanted it to go all the way across the grid, I set its column value to 1 / span 2. That means “Start at column line 1, and span across two columns.” I could have gotten the same result with the value 1 / 3, which means “Go from column line 1 to column line 3.” (Fig. 5)
Fig. 5: The grid items’ placement 
But realize: that’s just a diagram, not the actual layout situation. Not yet, at any rate. Something I want to be clear about here is that while you can explicitly assign all of your grid items to specific rows and columns, you don’t have to do so. Grid has a flow model that allows grid items to be automatically assigned to the next open grid cell, depending on the flow direction. In my case, I could have gotten away with only these rules:
#sitemast { grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; }
That would have ensured the masthead was two columns wide, and that the search and navigation divs were placed in the exact grid cells I wanted. That would have left the second row filled by navigation and search, and the rest of the grid cells open.
Given that, the unassigned items would be flowed into the grid in source order. The masthead would be placed in the first two-column row it could find, which turns out to be the first. Then the main div would flow into the first open cell: row 3, column 1. Extra would go into the next cell: row 3, column 2. And then the footer would be placed into row 4, column 1.
The end result would be exactly what’s shown in Fig. 5. The difference would be that if I had a special page where another div was added, it could throw off the whole layout, depending on where it appeared in the HTML. By explicitly assigning my layout pieces to the places I want them, I prevent a stray element upending everything.
Of course, if a child element of the body is added to a page, it will become a grid item. If I don’t give it a place in the grid, it will end up flowed into the first available grid cell. Since the lower-right cell (row 4, column 2) is unoccupied, that’s where the extra element would be placed, assuming it isn’t set to span two columns.
Accommodating the past
It’s easy enough to set up a grid, but when you drop grid items into it, they bring all of their existing styles in with them. That might not be a big deal in some cases, but in mine, it meant all of the margins and padding I’d used to keep the layout pieces apart from each other were now messing with the placement of the grid items. You can see this in Fig. 6, created using a local copy of the site.
Fig. 6: Grid + legacy = yoinks 
Ouch. It was time to override the pieces of the legacy layout styles I didn’t need, but of course I needed to keep them for browsers that don’t yet understand Grid.
So I wrapped the whole bit in an @supports block. Since I wanted to constrain the grid layout to wider displays, I put an @media block just inside @supports, and then proceeded to zero out or otherwise change the various margins and padding I didn’t need in a Grid context. Here’s how it turned out:
@supports (display: grid) { @media (min-width: 60.001em) { body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; position: static; padding: 0.25em 0 1em; } #main { grid-row: 3; grid-column: 1; margin-right: 0; margin-top: 1.25em; padding-top: 0; } .hpg #main { margin-top: 0; padding-top: 0; } #extra { grid-row: 3; grid-column: 2; position: static; top: 0; margin-top: 0; padding-top: 0.5em; margin-left: auto; } #navigate { grid-row: 2; grid-column: 1; position: static; margin-top: 1px; padding-bottom: 0; } #footer { grid-row: 4; grid-column: 1; margin-right: 0; } } }
I probably could refactor that to be more efficient, but for now, I’m going to leave it as-is. It makes clear what had to be done to which grid item—which ones needed to override position, which margins and padding needed to be changed, and so on. Let’s look at the end result (Fig. 7).
Fig. 7: Grid + @supports = yowza! 
You might be forgiven for thinking that this was much ado about not very much. Why go to all that effort just to make it look the same? The real power here, in what is admittedly a simple case, is how I no longer have to worry about overlap. The footer will always be below the main and extra divs, no matter which is taller. When I was using positioning, that wasn’t guaranteed.
Similarly, the navigation and search will always maintain a shared height, making sure neither will overlap with the content below them—and thanks to min-content, I don’t have to guess at how tall they might get. Grid just handles all that for me.
And remember, the layout still functions in old browsers just as it always did, using positioning. I didn’t “break” the site for browsers that don’t understand Grid. The more capable Grid layout is there, waiting for browsers like Firefox that understand it.
If you want to see all this live for yourself, head over to meyerweb.com and inspect elements in Firefox 52. There you’ll see a little grid icon next to the display: grid declaration on the body element. Click it, and Firefox will draw the grid lines on the page for you to check out.
Naming conventions
I mentioned earlier that it’s possible to name grid lines. I didn’t do it for my own styles because the grid I defined was so simple, but for more complicated grids, naming the lines might be useful.
Using the stripped-down version of the styles, the one without all the legacy overrides, naming the grid lines would look something like this:
body { display: grid; grid-template-rows: [masthead] 192px [navsearch] min-content [mainextra] min-content [footer] 1fr; grid-template-columns: [left] 1fr [middle] 20em [end]; }
Each of those square-bracketed words is assigned as a name to the corresponding grid line. (Fig. 8)
Fig. 8: Named grid lines 
Once those names are defined, you can refer to them in your grid-row and grid-column properties. For example:
#sitemast { grid-row: masthead; grid-column: left / span right; } #search { grid-row: navsearch; grid-column: middle; } #main { grid-row: mainextra; grid-column: left; } #extra { grid-row: mainextra; grid-column: middle; } #navigate { grid-row: navsearch; grid-column: left; } #footer { grid-row: footer; grid-column: left; }
There’s a lot more possible, too. Much like class names, you can assign multiple names to a grid line by supplying a space-separated list. Try this one for size:
grid-template-columns: [start left] 1fr [middle sidebar] 20em [right end];
You could then refer to any one of those names in your grid-column declaration. There’s no defined limit on the number of names, but remember what comes with great power.
In case you were wondering, you can mix grid line names and numbers, so something like grid-row: navsearch; grid-column: 2; is completely fine. You can use any name the browser can parse, which means you can use just about anything Unicode and your CSS file’s character encoding will handle. And heck, there’s also the very useful grid-area property…but that’s a subject for another day.
Grid and Flexbox
A question you may have is: now that we have Grid, do I throw away flexbox? Absolutely not! The two can and do work very well together.
Consider the navigation bar of my design. For years, it’s been laid out using an unordered list and float: left for the list items. Simplified a bit, the CSS and markup looks like this:
#navlinks { float: left; width: 100%; } #navlinks li { float: left; list-style: none; margin-left: 1px; }
<div id="navigate"> <ul id="navlinks"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li>><a href="…">Speaking</a></li> <li>>><a href="…">Leftovers</a></li> </ul> </div>
Why not display: inline-block instead of float: left? Because that literally wasn’t an option when I wrote the CSS for the navlinks, and I never got around to updating it. (Are you sensing a theme here?)
Now I have two much better options for arranging those links: Grid and Flexbox. I could define a grid there, which would go something like this:
#navlinks { display: grid; grid-template-columns: repeat(6,min-content); } #navlinks li { list-style: none; margin-left: 1px; }
That would essentially get the same result, only in a grid, which is far more robust than either floats or inline blocks. The advantage is that adding new items is easy.
On the other hand, I’d be using Grid, which is a two-dimensional layout system, for a one-dimensional piece of layout. It’s certainly possible to do this, but it feels a little like overkill, and it’s not really what Grid was designed to do. Flexbox, on the other hand, is designed for exactly these kinds of situations.
So I might write the following instead:
#navlinks { display: flex; justify-content: flex-start; flex-wrap: wrap; } #navlinks li { list-style: none; margin-left: 1px; }
Again, that would be basically the same result, but in a more robust fashion. In addition to keeping the links all lined up, the wrap value will let the links go to a second line if need be. And because the flexbox sits inside a grid item that’s part of a grid row whose height is min-content, any increase in height (due to line wrapping or whatever) will cause the entire row to become taller. That means the rows after it will move down to accommodate it.
And now that I look at the markup again, I’ve realized I can simplify that markup without needing to touch any grid styles. Instead of wrapping a list with a div, I can drop the div and reassign its ID to the list. So the markup can become:
<ul id="navigate"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li><a href="…">Speaking</a></li> <li><a href="…">Leftovers</a></li> </ul>
After adjusting the selectors in my CSS from #navlinks to #navigate, the resulting layout will be exactly as it was before. The ul will become a grid item and a flex container. That is a thing you can do.
The downside in my case would be dealing with any interactions between that change and my legacy layout, but it’s not a huge issue to solve. It’s just a matter of doing it.
Letdowns
So what are the down sides?  Not many, but they do exist.
Most fundamentally, there’s no way to define an overall page grid that has all items relate to it. In other words, if I say:
body { display: grid; grid-template-columns: repeat(16, 1fr); }
…then that sets up a 16-column flexible grid for the body element only, and its child elements are the only ones that can become grid items. I can’t reach down into the document tree and assign elements to be placed on that body grid. That’s the main reason I didn’t try to put the little sidebar bits on my blog posts into a shared grid: I literally can’t, at this point, unless I resort to ugly CSS or HTML hackery.
The capability to do such things is known as subgrid, and it hasn’t been implemented by any browsers as yet. There are questions as to exactly how it should or shouldn’t work, so there’s still plenty of hope that everything will work out in the end. It’s a disappointment that we don’t have it yet, and that lack restricts the full range of grid’s power, but hopefully only for a short while.
In the meantime, I’m sure people will come up with ways to work around this limitation. A basic workaround in this case: I could define a grid that applies to every blog post individually, and arrange the pieces of each post on those nested grids. The CSS would look something like:
div.post { display: grid; grid-template-columns: [meta] 10em [main] 1fr; grid-template-rows: [title] min-content [main] 1fr; }
With that, I could place the metadata, the title, and the post’s body text into the defined grid cells, using either grid line numbers or the grid names I set up. Something like:
div.post h3 { grid-column: 2; grid-row: title; } ul.meta { grid-column: meta; grid-row: main; } div.post div.text { grid-column: main; grid-row: main; }
The drawback is that the metadata is then constrained to be a specific width, instead of my being able to set a column that all metadata shares, and size it by the longest bit of content.  That’s no worse than right now, where I’m setting the floated metadata to an explicit width, so this doesn’t lose me anything. It’s just a (temporarily) missed opportunity to gain something.
Another limitation, one that may or may not be addressed, is that you cannot directly style grid cells. Suppose I’d wanted to put a box around the #extra sidebar, completely filling out that cell. I’d have to style the div. I can’t do something like this:
@grid-cell(2, 3) { background: teal; border: 1px solid; }
I mean, I’m not even..
http://ift.tt/2nHTrWF
0 notes
pattersondonaldblk5 · 7 years
Text
Practical CSS Grid: Adding Grid to an Existing Design
Understanding and using Grid is easier than you might expect. The day Grid support shipped in Firefox 52, I decided on the spur of the moment to convert the basic layout of my personal site to use Grid. And it was a fairly simple process—five minutes to write the grid styles, then 15-20 spent troubleshooting.
Grid allows us to literally define column and row grid lines, then attach elements to those lines in any order we choose. That may sound like tables, but Grid is so much more than tables ever dreamed. It means more responsive layouts, far more accessible documents, and far clearer markup than even floats and positioning ever afforded us.
It’s been decades since CSS first emerged, but it’s never contained a system anything like this. And Grid is already supported in both Chrome and Firefox, with Safari coming soon (its Technology Preview releases support Grid). A new era in digital design is dawning right now.
The way things used to be
Before we get to the Grid, allow me to take just a moment to explain the markup structure of meyerweb’s main pages, and the positioning-and-margins approach I’ve been using for, um, about 12 years now. Here’s how the markup is structured:
<body> <div id="sitemast">…</div> <div id="search">…</div> <div id="main">…</div> <div id="extra">…</div> <div id="navigate">…</div> <div id="footer">…</div> </body>
Some of the names are indiosyncratic holdovers from my early-2000s view of layout and naming conventions. #extra, for example, is what most of us would call #sidebar. #sitemast stands in for #masthead. And #footer is from the days before the actual <footer> element.
The divs (which should probably be sections these days, but never mind that now) are arranged the way they are so that if the CSS fails to load, or a speaking browser is used to browse the site, then the site’s masthead is first, the ability to search the site is second, and the main content of the page is third. After that, extra materials, site navigation, and the footer follow.
All of these were stitched together into a layout by absolutely positioning the navigate and search divs. The sitemast was set to be 192px tall, and both the navigate and search divs were given top: 192px; to show up just below it. In order to leave space for them to land, top margins were applied to the main and extra divs. (Fig. 1)
Fig. 1: meyerweb’s home page (foreshortened)  Constructing the grid
So that’s how things have been laid out since the middle of 2005, more or less. I fiddled with a flexbox layout at one point as an experiment, but never shipped it, because it felt clumsy to be using a one-dimensional layout tool to manage a two-dimensional layout. I probably should have converted the navigation bar to flexbox, but I got distracted by something else and never returned to the effort.
Besides, Grid was coming. In the run-up to Grid shipping in Firefox 52, I was focused on learning and teaching Grid, creating test cases, and using it to build figures for publication. And then, March 7th, 2017, it shipped to the public in Firefox 52. I tweeted and posted an article and demo I’d put together the night before, and sat back in wonderment that the day had finally come to pass. After 20+ years of CSS, finally, a real layout system, a set of properties and values designed from the outset for that purpose.
And then I decided, more or less in that moment, to convert my personal site to use Grid for its main-level layout. It took me less than five minutes to come up with the following:
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
That’s not all I had to do, but it’s the core. Let me break it down for you.
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; }
This part sets the body element to be a grid container and sets up the grid lines. When you make an element a grid container, all of its children become grid items. (If you’ve worked with flexbox, then this pattern will be familiar to you.) So with that display: grid, I turned all of the child divs into grid items.
Next come the rows in the grid. The values in grid-template-rows actually define separation distances between grid lines (the same is true of grid-template-columns, which we’ll get to in a moment). So the value 192px min-content min-content 1fr; means: “Go 192 pixels down from the top of the grid container and drop a grid line. Then drop another two such that they provide enough vertical space for the contents of the rows they define. Finally, leave one fr (fraction) of distance between the third grid line and the bottom of the grid container.” (Fig. 2)
Fig. 2: Defining the rows 
The value min-content is pretty cool. It means just what it says: “Take up the minimum amount of space needed to fit the contents.” So for the second row, the one that will contain the navigation bar and search field, it will be as tall as the taller of the two, and no taller.
Ditto for the third row, the one containing the main and extra divs. On the homepage, the main div will be taller. On subpages, that might not always be the case. In all circumstances, the row containing those two divs will always be tall enough to contain them both.
With the rows figured out, next come the columns. I decided to keep things simple and just set up two. If you look at meyerweb’s home page, it appears to have three columns, but that’s only true of blog posts—a substantial but minority part of the site—and the left-side “column” is more of a sidebar inside the main column.
In the original design, the sidebar (#extra) is 18em wide, with some extra space to keep it away from the main column. But the column also has to fit the search box, which is a bit wider. After some experimentation, I settled on a width of 20em. The rest was left to flex as 1fr. (Fig. 3)
Fig. 3: Defining the columns 
Now that I’ve used the fr unit twice, a few words of explanation are in order. fr stands for “fraction,” and means “a fraction of the available unconstrained space.” With the columns, there are two columns. One of them has an explicit width of 20em, which is thus constrained—there’s no room for flexibility. The rest of the column space is unconstrained—as the width of the grid container changes (say, due to changes of the browser window) the unconstrained space will change to be the container’s width minus the 20em of constrained space.
Imagine for a moment I’d decided to split the grid into four columns, with the rightmost being 20em wide and the rest being equal, flexible widths. That would have looked like:
grid-template-columns: 1fr 1fr 1fr 20em;
Alternatively, I could have written it as:
grid-template-columns: repeat(3, 1fr) 20em;
In any event, that would have caused the unconstrained space to be divided equally among the first three columns. If the grid container were 65em wide, the last column would be 20em wide, and the other three 15em each. (3 x 15 = 45; 45 + 20 = 65.) Shrink the grid container down 50em wide, and the first three columns would shrink to 10em each.
In my case, I wanted that first column to take all of the space not given to the constrained last column, so it got 1fr. The final result is shown in Fig. 4.
Fig. 4: The complete grid  Placing the items
With the grid lines set up, now it’s just a matter of attached the grid items to the grid lines. This happens automatically, using the grid-flow algorithm, but this is case where I want to place each thing in a specific place. That leads to the following:
#sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
For each of the six divs, I just said, “Pin your top to this row line, and your left to this column line.” I used line numbers because that’s all I gave myself. It’s possible to assign names to grid lines, but I didn’t. (But stay tuned for an example of this, later in the article!)
So, as an example, I set up the #main portion to start on the third row line and the first column line. That means it will, by default, fill out the space from the first to second column lines, and from the third to fourth row lines.
Almost all of the divs were set up in this way. The exception in this case is the @sitemast. It starts at the first column and row lines, but since I wanted it to go all the way across the grid, I set its column value to 1 / span 2. That means “Start at column line 1, and span across two columns.” I could have gotten the same result with the value 1 / 3, which means “Go from column line 1 to column line 3.” (Fig. 5)
Fig. 5: The grid items’ placement 
But realize: that’s just a diagram, not the actual layout situation. Not yet, at any rate. Something I want to be clear about here is that while you can explicitly assign all of your grid items to specific rows and columns, you don’t have to do so. Grid has a flow model that allows grid items to be automatically assigned to the next open grid cell, depending on the flow direction. In my case, I could have gotten away with only these rules:
#sitemast { grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; }
That would have ensured the masthead was two columns wide, and that the search and navigation divs were placed in the exact grid cells I wanted. That would have left the second row filled by navigation and search, and the rest of the grid cells open.
Given that, the unassigned items would be flowed into the grid in source order. The masthead would be placed in the first two-column row it could find, which turns out to be the first. Then the main div would flow into the first open cell: row 3, column 1. Extra would go into the next cell: row 3, column 2. And then the footer would be placed into row 4, column 1.
The end result would be exactly what’s shown in Fig. 5. The difference would be that if I had a special page where another div was added, it could throw off the whole layout, depending on where it appeared in the HTML. By explicitly assigning my layout pieces to the places I want them, I prevent a stray element upending everything.
Of course, if a child element of the body is added to a page, it will become a grid item. If I don’t give it a place in the grid, it will end up flowed into the first available grid cell. Since the lower-right cell (row 4, column 2) is unoccupied, that’s where the extra element would be placed, assuming it isn’t set to span two columns.
Accommodating the past
It’s easy enough to set up a grid, but when you drop grid items into it, they bring all of their existing styles in with them. That might not be a big deal in some cases, but in mine, it meant all of the margins and padding I’d used to keep the layout pieces apart from each other were now messing with the placement of the grid items. You can see this in Fig. 6, created using a local copy of the site.
Fig. 6: Grid + legacy = yoinks 
Ouch. It was time to override the pieces of the legacy layout styles I didn’t need, but of course I needed to keep them for browsers that don’t yet understand Grid.
So I wrapped the whole bit in an @supports block. Since I wanted to constrain the grid layout to wider displays, I put an @media block just inside @supports, and then proceeded to zero out or otherwise change the various margins and padding I didn’t need in a Grid context. Here’s how it turned out:
@supports (display: grid) { @media (min-width: 60.001em) { body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; position: static; padding: 0.25em 0 1em; } #main { grid-row: 3; grid-column: 1; margin-right: 0; margin-top: 1.25em; padding-top: 0; } .hpg #main { margin-top: 0; padding-top: 0; } #extra { grid-row: 3; grid-column: 2; position: static; top: 0; margin-top: 0; padding-top: 0.5em; margin-left: auto; } #navigate { grid-row: 2; grid-column: 1; position: static; margin-top: 1px; padding-bottom: 0; } #footer { grid-row: 4; grid-column: 1; margin-right: 0; } } }
I probably could refactor that to be more efficient, but for now, I’m going to leave it as-is. It makes clear what had to be done to which grid item—which ones needed to override position, which margins and padding needed to be changed, and so on. Let’s look at the end result (Fig. 7).
Fig. 7: Grid + @supports = yowza! 
You might be forgiven for thinking that this was much ado about not very much. Why go to all that effort just to make it look the same? The real power here, in what is admittedly a simple case, is how I no longer have to worry about overlap. The footer will always be below the main and extra divs, no matter which is taller. When I was using positioning, that wasn’t guaranteed.
Similarly, the navigation and search will always maintain a shared height, making sure neither will overlap with the content below them—and thanks to min-content, I don’t have to guess at how tall they might get. Grid just handles all that for me.
And remember, the layout still functions in old browsers just as it always did, using positioning. I didn’t “break” the site for browsers that don’t understand Grid. The more capable Grid layout is there, waiting for browsers like Firefox that understand it.
If you want to see all this live for yourself, head over to meyerweb.com and inspect elements in Firefox 52. There you’ll see a little grid icon next to the display: grid declaration on the body element. Click it, and Firefox will draw the grid lines on the page for you to check out.
Naming conventions
I mentioned earlier that it’s possible to name grid lines. I didn’t do it for my own styles because the grid I defined was so simple, but for more complicated grids, naming the lines might be useful.
Using the stripped-down version of the styles, the one without all the legacy overrides, naming the grid lines would look something like this:
body { display: grid; grid-template-rows: [masthead] 192px [navsearch] min-content [mainextra] min-content [footer] 1fr; grid-template-columns: [left] 1fr [middle] 20em [end]; }
Each of those square-bracketed words is assigned as a name to the corresponding grid line. (Fig. 8)
Fig. 8: Named grid lines 
Once those names are defined, you can refer to them in your grid-row and grid-column properties. For example:
#sitemast { grid-row: masthead; grid-column: left / span right; } #search { grid-row: navsearch; grid-column: middle; } #main { grid-row: mainextra; grid-column: left; } #extra { grid-row: mainextra; grid-column: middle; } #navigate { grid-row: navsearch; grid-column: left; } #footer { grid-row: footer; grid-column: left; }
There’s a lot more possible, too. Much like class names, you can assign multiple names to a grid line by supplying a space-separated list. Try this one for size:
grid-template-columns: [start left] 1fr [middle sidebar] 20em [right end];
You could then refer to any one of those names in your grid-column declaration. There’s no defined limit on the number of names, but remember what comes with great power.
In case you were wondering, you can mix grid line names and numbers, so something like grid-row: navsearch; grid-column: 2; is completely fine. You can use any name the browser can parse, which means you can use just about anything Unicode and your CSS file’s character encoding will handle. And heck, there’s also the very useful grid-area property…but that’s a subject for another day.
Grid and Flexbox
A question you may have is: now that we have Grid, do I throw away flexbox? Absolutely not! The two can and do work very well together.
Consider the navigation bar of my design. For years, it’s been laid out using an unordered list and float: left for the list items. Simplified a bit, the CSS and markup looks like this:
#navlinks { float: left; width: 100%; } #navlinks li { float: left; list-style: none; margin-left: 1px; }
<div id="navigate"> <ul id="navlinks"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li>><a href="…">Speaking</a></li> <li>>><a href="…">Leftovers</a></li> </ul> </div>
Why not display: inline-block instead of float: left? Because that literally wasn’t an option when I wrote the CSS for the navlinks, and I never got around to updating it. (Are you sensing a theme here?)
Now I have two much better options for arranging those links: Grid and Flexbox. I could define a grid there, which would go something like this:
#navlinks { display: grid; grid-template-columns: repeat(6,min-content); } #navlinks li { list-style: none; margin-left: 1px; }
That would essentially get the same result, only in a grid, which is far more robust than either floats or inline blocks. The advantage is that adding new items is easy.
On the other hand, I’d be using Grid, which is a two-dimensional layout system, for a one-dimensional piece of layout. It’s certainly possible to do this, but it feels a little like overkill, and it’s not really what Grid was designed to do. Flexbox, on the other hand, is designed for exactly these kinds of situations.
So I might write the following instead:
#navlinks { display: flex; justify-content: flex-start; flex-wrap: wrap; } #navlinks li { list-style: none; margin-left: 1px; }
Again, that would be basically the same result, but in a more robust fashion. In addition to keeping the links all lined up, the wrap value will let the links go to a second line if need be. And because the flexbox sits inside a grid item that’s part of a grid row whose height is min-content, any increase in height (due to line wrapping or whatever) will cause the entire row to become taller. That means the rows after it will move down to accommodate it.
And now that I look at the markup again, I’ve realized I can simplify that markup without needing to touch any grid styles. Instead of wrapping a list with a div, I can drop the div and reassign its ID to the list. So the markup can become:
<ul id="navigate"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li><a href="…">Speaking</a></li> <li><a href="…">Leftovers</a></li> </ul>
After adjusting the selectors in my CSS from #navlinks to #navigate, the resulting layout will be exactly as it was before. The ul will become a grid item and a flex container. That is a thing you can do.
The downside in my case would be dealing with any interactions between that change and my legacy layout, but it’s not a huge issue to solve. It’s just a matter of doing it.
Letdowns
So what are the down sides?  Not many, but they do exist.
Most fundamentally, there’s no way to define an overall page grid that has all items relate to it. In other words, if I say:
body { display: grid; grid-template-columns: repeat(16, 1fr); }
…then that sets up a 16-column flexible grid for the body element only, and its child elements are the only ones that can become grid items. I can’t reach down into the document tree and assign elements to be placed on that body grid. That’s the main reason I didn’t try to put the little sidebar bits on my blog posts into a shared grid: I literally can’t, at this point, unless I resort to ugly CSS or HTML hackery.
The capability to do such things is known as subgrid, and it hasn’t been implemented by any browsers as yet. There are questions as to exactly how it should or shouldn’t work, so there’s still plenty of hope that everything will work out in the end. It’s a disappointment that we don’t have it yet, and that lack restricts the full range of grid’s power, but hopefully only for a short while.
In the meantime, I’m sure people will come up with ways to work around this limitation. A basic workaround in this case: I could define a grid that applies to every blog post individually, and arrange the pieces of each post on those nested grids. The CSS would look something like:
div.post { display: grid; grid-template-columns: [meta] 10em [main] 1fr; grid-template-rows: [title] min-content [main] 1fr; }
With that, I could place the metadata, the title, and the post’s body text into the defined grid cells, using either grid line numbers or the grid names I set up. Something like:
div.post h3 { grid-column: 2; grid-row: title; } ul.meta { grid-column: meta; grid-row: main; } div.post div.text { grid-column: main; grid-row: main; }
The drawback is that the metadata is then constrained to be a specific width, instead of my being able to set a column that all metadata shares, and size it by the longest bit of content.  That’s no worse than right now, where I’m setting the floated metadata to an explicit width, so this doesn’t lose me anything. It’s just a (temporarily) missed opportunity to gain something.
Another limitation, one that may or may not be addressed, is that you cannot directly style grid cells. Suppose I’d wanted to put a box around the #extra sidebar, completely filling out that cell. I’d have to style the div. I can’t do something like this:
@grid-cell(2, 3) { background: teal; border: 1px solid; }
I mean, I’m not even..
http://ift.tt/2nHTrWF
0 notes
elizabetdfhmartin · 7 years
Text
Practical CSS Grid: Adding Grid to an Existing Design
Understanding and using Grid is easier than you might expect. The day Grid support shipped in Firefox 52, I decided on the spur of the moment to convert the basic layout of my personal site to use Grid. And it was a fairly simple process—five minutes to write the grid styles, then 15-20 spent troubleshooting.
Grid allows us to literally define column and row grid lines, then attach elements to those lines in any order we choose. That may sound like tables, but Grid is so much more than tables ever dreamed. It means more responsive layouts, far more accessible documents, and far clearer markup than even floats and positioning ever afforded us.
It’s been decades since CSS first emerged, but it’s never contained a system anything like this. And Grid is already supported in both Chrome and Firefox, with Safari coming soon (its Technology Preview releases support Grid). A new era in digital design is dawning right now.
The way things used to be
Before we get to the Grid, allow me to take just a moment to explain the markup structure of meyerweb’s main pages, and the positioning-and-margins approach I’ve been using for, um, about 12 years now. Here’s how the markup is structured:
<body> <div id="sitemast">…</div> <div id="search">…</div> <div id="main">…</div> <div id="extra">…</div> <div id="navigate">…</div> <div id="footer">…</div> </body>
Some of the names are indiosyncratic holdovers from my early-2000s view of layout and naming conventions. #extra, for example, is what most of us would call #sidebar. #sitemast stands in for #masthead. And #footer is from the days before the actual <footer> element.
The divs (which should probably be sections these days, but never mind that now) are arranged the way they are so that if the CSS fails to load, or a speaking browser is used to browse the site, then the site’s masthead is first, the ability to search the site is second, and the main content of the page is third. After that, extra materials, site navigation, and the footer follow.
All of these were stitched together into a layout by absolutely positioning the navigate and search divs. The sitemast was set to be 192px tall, and both the navigate and search divs were given top: 192px; to show up just below it. In order to leave space for them to land, top margins were applied to the main and extra divs. (Fig. 1)
Fig. 1: meyerweb’s home page (foreshortened)  Constructing the grid
So that’s how things have been laid out since the middle of 2005, more or less. I fiddled with a flexbox layout at one point as an experiment, but never shipped it, because it felt clumsy to be using a one-dimensional layout tool to manage a two-dimensional layout. I probably should have converted the navigation bar to flexbox, but I got distracted by something else and never returned to the effort.
Besides, Grid was coming. In the run-up to Grid shipping in Firefox 52, I was focused on learning and teaching Grid, creating test cases, and using it to build figures for publication. And then, March 7th, 2017, it shipped to the public in Firefox 52. I tweeted and posted an article and demo I’d put together the night before, and sat back in wonderment that the day had finally come to pass. After 20+ years of CSS, finally, a real layout system, a set of properties and values designed from the outset for that purpose.
And then I decided, more or less in that moment, to convert my personal site to use Grid for its main-level layout. It took me less than five minutes to come up with the following:
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
That’s not all I had to do, but it’s the core. Let me break it down for you.
body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; }
This part sets the body element to be a grid container and sets up the grid lines. When you make an element a grid container, all of its children become grid items. (If you’ve worked with flexbox, then this pattern will be familiar to you.) So with that display: grid, I turned all of the child divs into grid items.
Next come the rows in the grid. The values in grid-template-rows actually define separation distances between grid lines (the same is true of grid-template-columns, which we’ll get to in a moment). So the value 192px min-content min-content 1fr; means: “Go 192 pixels down from the top of the grid container and drop a grid line. Then drop another two such that they provide enough vertical space for the contents of the rows they define. Finally, leave one fr (fraction) of distance between the third grid line and the bottom of the grid container.” (Fig. 2)
Fig. 2: Defining the rows 
The value min-content is pretty cool. It means just what it says: “Take up the minimum amount of space needed to fit the contents.” So for the second row, the one that will contain the navigation bar and search field, it will be as tall as the taller of the two, and no taller.
Ditto for the third row, the one containing the main and extra divs. On the homepage, the main div will be taller. On subpages, that might not always be the case. In all circumstances, the row containing those two divs will always be tall enough to contain them both.
With the rows figured out, next come the columns. I decided to keep things simple and just set up two. If you look at meyerweb’s home page, it appears to have three columns, but that’s only true of blog posts—a substantial but minority part of the site—and the left-side “column” is more of a sidebar inside the main column.
In the original design, the sidebar (#extra) is 18em wide, with some extra space to keep it away from the main column. But the column also has to fit the search box, which is a bit wider. After some experimentation, I settled on a width of 20em. The rest was left to flex as 1fr. (Fig. 3)
Fig. 3: Defining the columns 
Now that I’ve used the fr unit twice, a few words of explanation are in order. fr stands for “fraction,” and means “a fraction of the available unconstrained space.” With the columns, there are two columns. One of them has an explicit width of 20em, which is thus constrained—there’s no room for flexibility. The rest of the column space is unconstrained—as the width of the grid container changes (say, due to changes of the browser window) the unconstrained space will change to be the container’s width minus the 20em of constrained space.
Imagine for a moment I’d decided to split the grid into four columns, with the rightmost being 20em wide and the rest being equal, flexible widths. That would have looked like:
grid-template-columns: 1fr 1fr 1fr 20em;
Alternatively, I could have written it as:
grid-template-columns: repeat(3, 1fr) 20em;
In any event, that would have caused the unconstrained space to be divided equally among the first three columns. If the grid container were 65em wide, the last column would be 20em wide, and the other three 15em each. (3 x 15 = 45; 45 + 20 = 65.) Shrink the grid container down 50em wide, and the first three columns would shrink to 10em each.
In my case, I wanted that first column to take all of the space not given to the constrained last column, so it got 1fr. The final result is shown in Fig. 4.
Fig. 4: The complete grid  Placing the items
With the grid lines set up, now it’s just a matter of attached the grid items to the grid lines. This happens automatically, using the grid-flow algorithm, but this is case where I want to place each thing in a specific place. That leads to the following:
#sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #main { grid-row: 3; grid-column: 1; } #extra { grid-row: 3; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; } #footer { grid-row: 4; grid-column: 1; }
For each of the six divs, I just said, “Pin your top to this row line, and your left to this column line.” I used line numbers because that’s all I gave myself. It’s possible to assign names to grid lines, but I didn’t. (But stay tuned for an example of this, later in the article!)
So, as an example, I set up the #main portion to start on the third row line and the first column line. That means it will, by default, fill out the space from the first to second column lines, and from the third to fourth row lines.
Almost all of the divs were set up in this way. The exception in this case is the @sitemast. It starts at the first column and row lines, but since I wanted it to go all the way across the grid, I set its column value to 1 / span 2. That means “Start at column line 1, and span across two columns.” I could have gotten the same result with the value 1 / 3, which means “Go from column line 1 to column line 3.” (Fig. 5)
Fig. 5: The grid items’ placement 
But realize: that’s just a diagram, not the actual layout situation. Not yet, at any rate. Something I want to be clear about here is that while you can explicitly assign all of your grid items to specific rows and columns, you don’t have to do so. Grid has a flow model that allows grid items to be automatically assigned to the next open grid cell, depending on the flow direction. In my case, I could have gotten away with only these rules:
#sitemast { grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; } #navigate { grid-row: 2; grid-column: 1; }
That would have ensured the masthead was two columns wide, and that the search and navigation divs were placed in the exact grid cells I wanted. That would have left the second row filled by navigation and search, and the rest of the grid cells open.
Given that, the unassigned items would be flowed into the grid in source order. The masthead would be placed in the first two-column row it could find, which turns out to be the first. Then the main div would flow into the first open cell: row 3, column 1. Extra would go into the next cell: row 3, column 2. And then the footer would be placed into row 4, column 1.
The end result would be exactly what’s shown in Fig. 5. The difference would be that if I had a special page where another div was added, it could throw off the whole layout, depending on where it appeared in the HTML. By explicitly assigning my layout pieces to the places I want them, I prevent a stray element upending everything.
Of course, if a child element of the body is added to a page, it will become a grid item. If I don’t give it a place in the grid, it will end up flowed into the first available grid cell. Since the lower-right cell (row 4, column 2) is unoccupied, that’s where the extra element would be placed, assuming it isn’t set to span two columns.
Accommodating the past
It’s easy enough to set up a grid, but when you drop grid items into it, they bring all of their existing styles in with them. That might not be a big deal in some cases, but in mine, it meant all of the margins and padding I’d used to keep the layout pieces apart from each other were now messing with the placement of the grid items. You can see this in Fig. 6, created using a local copy of the site.
Fig. 6: Grid + legacy = yoinks 
Ouch. It was time to override the pieces of the legacy layout styles I didn’t need, but of course I needed to keep them for browsers that don’t yet understand Grid.
So I wrapped the whole bit in an @supports block. Since I wanted to constrain the grid layout to wider displays, I put an @media block just inside @supports, and then proceeded to zero out or otherwise change the various margins and padding I didn’t need in a Grid context. Here’s how it turned out:
@supports (display: grid) { @media (min-width: 60.001em) { body { display: grid; grid-template-rows: 192px min-content min-content 1fr; grid-template-columns: 1fr 20em; } #sitemast { grid-row: 1; grid-column: 1 / span 2; } #search { grid-row: 2; grid-column: 2; position: static; padding: 0.25em 0 1em; } #main { grid-row: 3; grid-column: 1; margin-right: 0; margin-top: 1.25em; padding-top: 0; } .hpg #main { margin-top: 0; padding-top: 0; } #extra { grid-row: 3; grid-column: 2; position: static; top: 0; margin-top: 0; padding-top: 0.5em; margin-left: auto; } #navigate { grid-row: 2; grid-column: 1; position: static; margin-top: 1px; padding-bottom: 0; } #footer { grid-row: 4; grid-column: 1; margin-right: 0; } } }
I probably could refactor that to be more efficient, but for now, I’m going to leave it as-is. It makes clear what had to be done to which grid item—which ones needed to override position, which margins and padding needed to be changed, and so on. Let’s look at the end result (Fig. 7).
Fig. 7: Grid + @supports = yowza! 
You might be forgiven for thinking that this was much ado about not very much. Why go to all that effort just to make it look the same? The real power here, in what is admittedly a simple case, is how I no longer have to worry about overlap. The footer will always be below the main and extra divs, no matter which is taller. When I was using positioning, that wasn’t guaranteed.
Similarly, the navigation and search will always maintain a shared height, making sure neither will overlap with the content below them—and thanks to min-content, I don’t have to guess at how tall they might get. Grid just handles all that for me.
And remember, the layout still functions in old browsers just as it always did, using positioning. I didn’t “break” the site for browsers that don’t understand Grid. The more capable Grid layout is there, waiting for browsers like Firefox that understand it.
If you want to see all this live for yourself, head over to meyerweb.com and inspect elements in Firefox 52. There you’ll see a little grid icon next to the display: grid declaration on the body element. Click it, and Firefox will draw the grid lines on the page for you to check out.
Naming conventions
I mentioned earlier that it’s possible to name grid lines. I didn’t do it for my own styles because the grid I defined was so simple, but for more complicated grids, naming the lines might be useful.
Using the stripped-down version of the styles, the one without all the legacy overrides, naming the grid lines would look something like this:
body { display: grid; grid-template-rows: [masthead] 192px [navsearch] min-content [mainextra] min-content [footer] 1fr; grid-template-columns: [left] 1fr [middle] 20em [end]; }
Each of those square-bracketed words is assigned as a name to the corresponding grid line. (Fig. 8)
Fig. 8: Named grid lines 
Once those names are defined, you can refer to them in your grid-row and grid-column properties. For example:
#sitemast { grid-row: masthead; grid-column: left / span right; } #search { grid-row: navsearch; grid-column: middle; } #main { grid-row: mainextra; grid-column: left; } #extra { grid-row: mainextra; grid-column: middle; } #navigate { grid-row: navsearch; grid-column: left; } #footer { grid-row: footer; grid-column: left; }
There’s a lot more possible, too. Much like class names, you can assign multiple names to a grid line by supplying a space-separated list. Try this one for size:
grid-template-columns: [start left] 1fr [middle sidebar] 20em [right end];
You could then refer to any one of those names in your grid-column declaration. There’s no defined limit on the number of names, but remember what comes with great power.
In case you were wondering, you can mix grid line names and numbers, so something like grid-row: navsearch; grid-column: 2; is completely fine. You can use any name the browser can parse, which means you can use just about anything Unicode and your CSS file’s character encoding will handle. And heck, there’s also the very useful grid-area property…but that’s a subject for another day.
Grid and Flexbox
A question you may have is: now that we have Grid, do I throw away flexbox? Absolutely not! The two can and do work very well together.
Consider the navigation bar of my design. For years, it’s been laid out using an unordered list and float: left for the list items. Simplified a bit, the CSS and markup looks like this:
#navlinks { float: left; width: 100%; } #navlinks li { float: left; list-style: none; margin-left: 1px; }
<div id="navigate"> <ul id="navlinks"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li>><a href="…">Speaking</a></li> <li>>><a href="…">Leftovers</a></li> </ul> </div>
Why not display: inline-block instead of float: left? Because that literally wasn’t an option when I wrote the CSS for the navlinks, and I never got around to updating it. (Are you sensing a theme here?)
Now I have two much better options for arranging those links: Grid and Flexbox. I could define a grid there, which would go something like this:
#navlinks { display: grid; grid-template-columns: repeat(6,min-content); } #navlinks li { list-style: none; margin-left: 1px; }
That would essentially get the same result, only in a grid, which is far more robust than either floats or inline blocks. The advantage is that adding new items is easy.
On the other hand, I’d be using Grid, which is a two-dimensional layout system, for a one-dimensional piece of layout. It’s certainly possible to do this, but it feels a little like overkill, and it’s not really what Grid was designed to do. Flexbox, on the other hand, is designed for exactly these kinds of situations.
So I might write the following instead:
#navlinks { display: flex; justify-content: flex-start; flex-wrap: wrap; } #navlinks li { list-style: none; margin-left: 1px; }
Again, that would be basically the same result, but in a more robust fashion. In addition to keeping the links all lined up, the wrap value will let the links go to a second line if need be. And because the flexbox sits inside a grid item that’s part of a grid row whose height is min-content, any increase in height (due to line wrapping or whatever) will cause the entire row to become taller. That means the rows after it will move down to accommodate it.
And now that I look at the markup again, I’ve realized I can simplify that markup without needing to touch any grid styles. Instead of wrapping a list with a div, I can drop the div and reassign its ID to the list. So the markup can become:
<ul id="navigate"> <li><a href="…">Archives</a></li> <li><a href="…">CSS</a></li> <li><a href="…">Toolbox</a></li> <li><a href="…">Writing</a></li> <li><a href="…">Speaking</a></li> <li><a href="…">Leftovers</a></li> </ul>
After adjusting the selectors in my CSS from #navlinks to #navigate, the resulting layout will be exactly as it was before. The ul will become a grid item and a flex container. That is a thing you can do.
The downside in my case would be dealing with any interactions between that change and my legacy layout, but it’s not a huge issue to solve. It’s just a matter of doing it.
Letdowns
So what are the down sides?  Not many, but they do exist.
Most fundamentally, there’s no way to define an overall page grid that has all items relate to it. In other words, if I say:
body { display: grid; grid-template-columns: repeat(16, 1fr); }
…then that sets up a 16-column flexible grid for the body element only, and its child elements are the only ones that can become grid items. I can’t reach down into the document tree and assign elements to be placed on that body grid. That’s the main reason I didn’t try to put the little sidebar bits on my blog posts into a shared grid: I literally can’t, at this point, unless I resort to ugly CSS or HTML hackery.
The capability to do such things is known as subgrid, and it hasn’t been implemented by any browsers as yet. There are questions as to exactly how it should or shouldn’t work, so there’s still plenty of hope that everything will work out in the end. It’s a disappointment that we don’t have it yet, and that lack restricts the full range of grid’s power, but hopefully only for a short while.
In the meantime, I’m sure people will come up with ways to work around this limitation. A basic workaround in this case: I could define a grid that applies to every blog post individually, and arrange the pieces of each post on those nested grids. The CSS would look something like:
div.post { display: grid; grid-template-columns: [meta] 10em [main] 1fr; grid-template-rows: [title] min-content [main] 1fr; }
With that, I could place the metadata, the title, and the post’s body text into the defined grid cells, using either grid line numbers or the grid names I set up. Something like:
div.post h3 { grid-column: 2; grid-row: title; } ul.meta { grid-column: meta; grid-row: main; } div.post div.text { grid-column: main; grid-row: main; }
The drawback is that the metadata is then constrained to be a specific width, instead of my being able to set a column that all metadata shares, and size it by the longest bit of content.  That’s no worse than right now, where I’m setting the floated metadata to an explicit width, so this doesn’t lose me anything. It’s just a (temporarily) missed opportunity to gain something.
Another limitation, one that may or may not be addressed, is that you cannot directly style grid cells. Suppose I’d wanted to put a box around the #extra sidebar, completely filling out that cell. I’d have to style the div. I can’t do something like this:
@grid-cell(2, 3) { background: teal; border: 1px solid; }
I mean, I’m not even..
http://ift.tt/2nHTrWF
0 notes