Complex responsive layout - html

I have a complex layout design and I want to make it responsive. The problem is I don't know-
How I should approach this design (how to structure the html to achieve this)
flex?
grid?
absolute positioning?
Is it even possible to make this kind of layout without making 2 sets of everything and hiding one of them for desktop and vice versa?
This is the layout that I'm talking about:
Desktop layout
Mobile layout
I don't even need the code part for this implementation.
I just need to know if this is possible and if so how do I do that(which structure, what display type for the parent etc)
If not, what are the work arounds?
Changing the design is the final resort but i really don't want to do that.

Have the three elements as siblings, in the order you want them displayed on mobile.
Detach the blue element's background from its contents (conceptually) - they are not the same thing.
Render the yellow and blue (transparent on desktop) elements as right column (using grid or flex), while placing the blue background under them (I used the parent's :before) for positioning the background.
I purposefully placed an inline red border on the contents of the blue element, to highlight its position.
You're pretty much done. The rest are implementation details.
I challenge you to do it yourself before looking at the solution below.
Key points of the solution below:
Note the required position: relative on the parent and also the position:relative; z-index: 0 on the "right-column" elements (without those rules they're rendered below the :before).
I used min-heights here to size the elements (as they're empty) but, once you place content inside them, you could/should remove the min-heights.
You'll probably need to adjust the margins/paddings to suit your needs, once you place real content inside them, but that should be fairly straight-forward.
Here it is:
body {
margin: 0;
}
* {
box-sizing: border-box;
}
.red {
background-color: #ff8584;
padding: 1rem;
}
.yellow {
background-color: #fff742;
}
.green {
background-color: #c0ff72;
}
.blue {
background-color: #72ccff;
}
.red>* {
min-height: 100px;
margin-bottom: 1rem;
}
.red>*:last-child {
margin-bottom: 0;
}
#media (min-width: 768px) {
.red {
position: relative;
display: grid;
grid-template: 'green yellow' auto 'green blue' 1fr / 1fr 1fr;
min-height: 100vh;
grid-column-gap: 1rem;
}
.red:before {
content: '';
position: absolute;
background-color: #72ccff;
top: 1rem;
right: 1rem;
bottom: 1rem;
left: calc(50% + .5rem);
}
.red>* {
margin-bottom: 0;
}
.yellow {
margin: 1rem 1rem 0;
grid-area: yellow;
}
.green {
grid-area: green;
}
.blue {
grid-area: blue;
}
.yellow,
.blue {
position: relative;
z-index: 0;
}
.blue {
background-color: transparent;
}
}
<div class="red">
<div class="yellow"></div>
<div class="green"></div>
<div class="blue" style="border: 1px solid red"></div>
</div>
I also wrote an SCSS version, making the background properties #mixins and the $spacer a variable, so they could be easily replaced.

Even though #tao answered this question with an better answer, I'd also like to provide a less "professional" answer but works great.
My answer uses grid-template-areas and media queries. In addition to that, I'm not going to select my own answer as accepted answer(Even though this is what I used in the end)
https://codepen.io/absanthosh/pen/WNRqLYQ?editors=1100

I suppose what you could do is:
In the HTML code make the order of elements yellow-green-blue, all three as siblings and direct children of red.
For the mobile version there will be no position settings necessary, no flex or anything, just regular divs with default (= full) width, with some padding and margins.
For the desktop version make green and blue inline-blocks, with a little less than 50% width, all taking into account according paddings and margins. Apply position: relative to red and position: absolute to yellow, which gets a width of around 45% (again, depending on paddings and margins) and a right setting that places it where you want it (as a percentage value). The top setting for yellow depends on the padding/margins of red and blue.

Related

How to achieve this sticking out image layout without using negative margins?

This is the layout image:
As you can see in the image, the images of the phones are sticking out of the blue container.
I have tried several things, such as:
I tried to use a grid with 5 rows where a <div> tag expanded all the rows and was set to have its background as the phone images. Then I set the blue background box to use only the rows form 2-4.
This somehow did the trick, but when the browser window was resized the image started to shrink and be positioned in a funky way.
As a newcomer to CSS I want to avoid negative margins because I have read they are "evil".
Is there any way to accomplish this in a clean/non-hacky way?
You can use the transform property to move the images where they need to be.
You'll need to build your layout as usual, but without the images being raised/lowered outside their default position.
Once you've done that, you can use transform: translateY(-100px) to raise or lower the images into their target position.
A quick example of this can be shown using <div> tags:
/* Setup some basic layouts to mimic the layout required */
.container {
padding-top: 100px;
padding-bottom: 100px;
}
.banner {
height: 200px;
background: blue;
display: flex;
justify-content: center;
align-items: center;
}
.image-1 {
height: 200px;
width: 200px;
background: red;
transform: translateY(-50px); /* move the image up */
}
.image-2 {
height: 200px;
width: 200px;
background: green;
transform: translateY(50px); /* move the image down */
}
.example-filler {
}
<div class="container">
<div class="banner">
<div class="image-1"></div>
<div class="image-2"></div>
<div class="example-filler">Lorem ipsum</div>
</div>
</div>
If you don't wan't to use negative margins (which are fine in this situation). You can try to give these styles to your image.
img {
position: relative;
top: -100px;
}
You can learn more about the "position" property here.
It is very important for beginners to understand how it works.

What would a negative margin on all four sides do in CSS?

If I wrote this:
#element {
margin-top: -50px;
}
By general rule, it would move the element upwards by 50 pixels.
Recently, I accidentally used this bit of code instead:
.elements {
margin: -50px;
}
So I had these <div> tags, one beneath the other, and by writing margin: -50px; they all somehow got closer together.
But thinking in retrospect, I don't really see how this worked. The size of the elements didn't change (as far as I know, as they contained child elements, and the child elements were closer together as well), and they didn't seem to zoom in size or anything.
I did some research online, but all I could find was for negative margins on one or two sides at most.
Is there an explanation to this? What actually happens? Maybe it's because I'm using Google Chrome, and maybe nothing happens in other browsers?
Tha margin is not added to the appearance of the element but rather to its bounds, so basically your element looks e.g. 200x200 but its bounds are equal to that of an element of 100x100 since you substract 50px from every side. Try it for yourself:
Fiddle here.
HTML:
<div class="e1"><div></div></div>
<div class="e2"><div></div></div>
CSS:
body {
padding: 100px;
}
div {
width: 200px;
height: 200px;
float: left;
margin: -50px;
}
.e1 {
background: red;
}
.e2 {
background: yellow;
}
.e1>div, .e2>div {
width: 100px;
height: 100px;
outline: 1px solid blue;
margin: 50px;
}
I've added a padding to the body to make the elements be pushed down so you can see the overlap they cause. Updated so you can see the bounds of the squares that result.

Double border with only one element

I was trying to get a double bordered (underlined) header. First one is full width, second is just text width. Borders should overlap
There is an easy solution with two elements nested like that:
<h1><span>Title</span></h1>
and css:
h1 {
border-bottom: 1px solid red;
}
h1 span {
display: inline-block;
padding: 0 0 10px;
margin-bottom: -1px;
border-bottom: 1px solid blue;
}
Span has inline-block display property so it has right width.
I'm wondering if it's possible to get same effect with :after, :before selectors and only h1 element.
It can be done. I've used vw units.
Take a look at this Working Fiddle
HTML:
<h1 class="SpecialBorder">Title</h1>
CSS:
*
{
margin: 0;
padding: 0;
}
.SpecialBorder
{
display: inline-block;
position: relative;
}
.SpecialBorder:before , .SpecialBorder:after
{
content:'';
position: absolute;
left: 0;
bottom: 0;
}
.SpecialBorder:before
{
width: 100vw;
border-bottom: 1px solid red;
}
.SpecialBorder:after
{
width: 100%;
border-bottom: 1px solid blue;
}
Explanation:
the before & after pseudo elements are the ones that draw the borders.
both of them are empty elements. with a certain width that causes their border to be visible.
they are absolutely position at the bottom of their <h1> parent.
before: responsible for the red border. so his width is set to '100%' of view port.
after: responsible for the red border. so hes width is set to 100% of his parent (the <h1>), that's why the h1 is set to `display:inline-block;" (so it will span ony just as his content)
vw unit is supported by new browsers only.
notice that if you cant use vw units, you can still make something familiar to that.
delete the display:inline-block; from h1 (causing it to span all the way again)
change the width of before to 100% (to make it span all the way),
change the with of after to some fixed value of your choice.
Edit: as thgaskell stated in th comment,
there's a bug where vw units don't update properly on webkit
browsers when the window is resized.
Edit 2:
for making elements to show after the title, you can use a <br /> tag, or clearing techniques like showed here.
I'm not sure if that's what you want, but you could do these rules:
h1 {
...
}
/* here are the direct children of every h1 */
h1>* {
...
}
::after and ::before selectors would make sense when inserting new content (note the double colons). Here's some MDN on ::after selector and some examples:
https://developer.mozilla.org/en-US/docs/Web/CSS/::after

How to make children auto fit parent's width only with CSS?

I have a server-side component that generates a fluid layout "toolbar" using DIV without fixed width, generating many A inside it.
Then I need customize that layout to make all A tags auto fit to the parent width. But the number of children is variable and the parent's width isn't known (it auto fits itself to the window).
I made some tests with this Fiddle: http://jsfiddle.net/ErickPetru/6nSEj/1/
But I can't find a way to make it dynamic (uncomment the last A tag to see how it ins't working, lol).
I can't change the server-side sources to gerenate HTML with fixed width. And I really would like to solve it only with CSS if there is any way, even that with JavaScript I could achieve that result.
How can I make all the children auto-fit itself to the parent's width independently of the number of children?
You can use display: table-cell:
See: http://jsfiddle.net/6nSEj/12/ (or with 5 children)
This won't work in IE7 because that browser simply doesn't support display: table and friends.
div.parent {
..
width: 100%;
display: table;
table-layout: fixed;
}
div.parent a {
..
display: table-cell;
}
This is already a pretty old question. Although the answers given attended well at the time, nowadays the Flexible Box Layout offers the same result with much more simplicity, with good support in all modern browsers. I strongly recommend it!
/* Important parts */
.parent {
display: flex;
}
.parent a {
flex: 1;
}
/* Decoration */
.parent {
padding: 8px;
border: 1px solid #ccc;
background: #ededed;
}
.parent a {
line-height: 26px;
text-align: center;
text-decoration: none;
border: 1px solid #ccc;
background: #dbdbdb;
color: #111;
}
<div class="parent">
Some
Other
Any
</div>
<br>
<div class="parent">
Some
Other
Any
One More
Last
</div>
For now many use jQuery as a solution to this problem. All you need is one line. This is from your fiddle.
$("div.parent a").css("width", (($("div.parent").width() / $("div.parent a").length ) -2) + "px");

An expanding middle in CSS

How would I go about designing a website which has a fixed height header and footer (attached to the top and bottom of the browser window) but an expanding middle. The scroll bars would be only for the middle (orange section in diagram) so that the rest of the page would never need to scroll. I have drawn a mock-up below to explain more clearly.
Ideally it needs to be entirely implemented in CSS and HTML (no javascript fiddles!). I've got quite far with this problem but I can't force the orange section to fill up the remaining space when it isn't full(whatever it's content) and start scrolling if it overflows.
I think this is what you want:
Live Demo (edit)
HTML:
<div id="header">Patrick</div>
<div id="content">..</div>
<div id="footer">Beardmore</div>
CSS:
html, body {
margin: 0;
padding: 0;
border: 0;
overflow: hidden
}
#header, #content, #footer {
position: absolute;
left: 0;
width: 100%
}
#header {
top: 0;
height: 100px;
background: #ccc
}
#content {
top: 100px;
bottom: 100px;
overflow-y: auto
}
#footer {
bottom: 0;
height: 100px;
background: #ccc
}
It's called StickyFooter or the "footer push" method. It's all over the web, but this is the best option I've found:
http://ryanfait.com/sticky-footer/
An old question, but flexbox has given us a super easy way to implement this pattern, a familiar variation on the 'Holy Grail' layout:
body {
/*set container to vertical (column) flex mode, ensure body is full height*/
display: flex;
min-height: 100vh;
flex-direction: column;
}
header, footer {
/*more or less equivalent to min-height:50px*/
flex-basis:50px
}
header {
background-color: #7AEE2D;
}
main {
background-color: #EBAE30;
/*tell main section to expand to fill available space, this is same as flex 1; or flex:1 1 auto;*/
flex-grow:1;
}
footer {
background-color: #34A4E7;
}
<header>header</header>
<main>main</main>
<footer>footer</footer>
A note about the syntax: I've used the "atomic" flexbox CSS properties here for simplicity, but in the wild you are more likely to run into the shorthand syntax using the flex keyword by itself. The default values for the 3 properties you can set on flex items (children of a display:flex container) are:
Initial value as each of the properties of the shorthand: flex-grow: 0
flex-shrink: 1 flex-basis: auto
Using flex, there are multiple ways to compose these properties, specifying one, two, or three values, and those values can by keywords, unit lengths (2px), or unitless grow/shrink ratios 2. Many different "overloads" are available, depending on your arguments.
For example, flex-basis:50px could've been flex:50px, flex:0 1 50px, and flex-grow:1 could have been flex 1; or flex:1 1 auto;. It's still not as bad as some other CSS shorthands I can think of (position, I'm looking at you). The 'flex' shorthand syntax MDN page has more details.