How can I implement this responsive flexbox layout? - html

I'm trying to design a simple and responsive homepage layout. To make things more efficient and easy (hopefully) I'm using flexbox.
My idea is to have a centered main title ("This is Flexbox") with two clickable buttons below it ("Try it" and "About").
I also added a media query to try and adapt the flexbox settings differently in screens that are below 640px width, but I just can't make flexbox work both ways; more specifically, I'd like the two buttons to stack on top of each other as columns when the screen width is below 640px, as well as modify their sizes and keep them centered.
Now, my problems are:
link color does not work and remains blue-ish instead of orange;
the title box is as large as the entire page and not as the text it contains;
the media query, with which I tried to use flexbox differently in screens that are 640px or larger, seems to be "overridden" by the flexbox commands outside the media query itself;
the command: flex-flow:column does not work.
CodePen code link
a {
text-decoration: none;
}
body {
font-family: 'century gothic', sans-serif;
background: black;
box-sizing: border-box;
}
#media(min-width:640px) {
.buttons {
display: flex;
flex-flow: row;
justify-content: center;
color: ivory;
margin: 0 100;
}
.buttons .btns {
border: solid red 1px;
background: #ff7b25;
padding: 10;
border-radius: 10px;
color: ivory;
}
.buttons .btns:hover {
background-color: white;
color: #ff7b25;
transition: .5s;
}
}
.buttons {
display: flex;
justify-content: center;
flex-flow: column wrap;
border: solid red 1px;
margin: 10 50;
color: ivory;
}
.buttons .btns {
text-align: center;
border: solid red 1px;
background: #ff7b25;
border-radius: 10px;
color: ivory;
margin: 10px;
}
.buttons .btns:hover {
background-color: ivory;
color: #ff7b25;
transition: .5s;
}
.title {
border: solid red 1px;
margin-top: 150px;
display: flex;
justify-content: center;
}
.title .t1 {
border: solid red 1px;
background: #2f2a2a;
padding: 5 10;
color: ivory;
}
.title .t2 {
border: solid red 1px;
color: ivory;
letter-spacing: 3px;
font-style: oblique;
background: #ff7b25;
padding: 5 10;
}
<div class="title">
<div class="t1">
<h1>This is</h1>
</div>
<div class="t2">
<h1>FLEXBOX</h1>
</div>
</div>
<div class="buttons">
<div class="btns">
<h3>Free trial</h3>
</div>
<div class="btns">
<h3>About</h3>
</div>
</div>

Link colors:
You need to add the color attribute in your a selector, not in .btns.
Title box:
In order to be centered properly, your flexbox should be as wide as the site, with its elements centered, that's correct. Just apply no styling to it so its width isn't visible. If you need a box around the children, you should wrap them in a container (which then becomes the flex item).
Media query:
Your CSS order is wrong, put the #media at the end, as it is, you apply the #media rule and then always override it with your non-specific CSS further down.

let me tackle your problems one after another:
link color does not work and remains blue-ish instead of orange
By adding color: inherit; to a {} you can make it respect the color. (Read more about cascade to learn more).
the title box is as large as the entire page and not as the text it contains
Naturally, since it is a „block” element (instead of an „inline” one). You can remove the border definition from .title to make it look like you expect?
the media query, with wich I tried to use flexbox differently in screens that are 640px or larger, seems to be "overridden" by the flexbox commands outside the media query itself
In CSS the later definitions overwrite earlier ones.
Try moving the media query towards the end of the file.
the command: "flex-flow:column" does not work.
Could you elaborate?

I'm only going to go into flex-flow, because I see that the other answers are pretty well answered.
flex-flow is shorthand for two CSS properties, flex-direction, and flex-wrap. I believe that just putting column flex-flow won't be sufficient. I think you need to add another value wrap or no wrap.
flex-flow: column wrap;

Related

How can I make this layout responsive?

<div class="parentdiv">
<div><img src="img/noimage.png"></div>
<div class="bottom">
<p class="text1">Text1</p>
<div class="btn_area">
Text2
Text3
</div>
</div>
</div>
I've barely managed to make this layout with bunch of floats, margins, tops and lefts but the layout breaks at practically any other screen ratios.
I feel that I shouldn't be spamming float and margins when creating a layout. Are there any better options to build such layout that does not break catastrophically on ratio change?
I've tried googling but what I've found was mostly making asingle div or image responsive which I've succeeded, but can't apply it to my layout.
Try this out and see if you understand whats going on. I will also add a Tutorial for CSS-Flex as a link at the bottom. Make sure that you always post the code you have, that means HTML and CSS for a CSS Question etc. Im just answering directly here cause your Question implies, that you just tried floats. This solution here probably requires you to change some things to perfectly fit, so you can practice a bit with it:
body {
width: 100vw;
height: 100vh;
/*We need a fixed height and width of the parent-Element to make % values work in the child elements*/
}
.parentdiv {
width: 100%;
/*Careful, when your Content inside of this gets close to the maximum width and height of this div you need to change width: 100% or the layout will overflow*/
padding: 25px;
height: 50%;
/*This makes the Element a Flexbox-Element*/
display: flex;
/*sets the direction and the behaviour*/
flex-flow: row nowrap;
}
.left-area {
width: 40%;
display: flex;
flex-flow: row nowrap;
/*the following 2 attributes define where the content is positioned inside the Flexbox-element*/
justify-content: start;
align-items: start;
}
.left-area img {
width: 6rem;
height: 6rem;
/*I used the border to make the Img Look like yours cause i dont have the file*/
border: 1px solid grey;
border-radius: 50%;
}
.text1 {
font-size: 1.5rem;
color: grey;
font-weight: bold;
}
.right-area {
width: 15%;
height: 50%;
display: flex;
/*Column-Reverse means that you have a column but you start at the bottom of it, like it is standing on its head*/
flex-flow: column-reverse nowrap;
}
.btn_area{
width: 100%;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
}
.text2 {
font-size: 1.2rem;
color: #7ad0bc;
font-weight: bold;
}
.text3 {
font-size: 1.2rem;
color: #d96060;
font-weight: bold;
}
<div class="parentdiv">
<div class="left-area">
<img src="img/noimage.png" alt="no image available">
<p class="text1">Text1</p>
</div>
<div class="right-area">
<div class="btn_area">
Text2
Text3
</div>
</div>
</div>
Tutorials for CSS-Flex: Tutorial Help-sheet

Text doesn't get right aligned in display flex

Please note that it's not a simple "how do I get XXX" question. I can achieve the look I'm going for but I'm surprised on how. Hence, I fear that I'm doing it in a bad way.
As shown in this fiddle, the text inside the divs is left aligned and the CSS text-adjust isn't effective. I suspect it's because the width of the div somehow is void, because setting the width to e.g. 15% for each numeric cell causes the expected behavior.
Of course, setting the width collides with the very point of enjoying flex, so that's not the right way to go. I'm reaching the requested look by applying justify-content but my understanding is that controlling the alignment that way (from the container div imposing placement on the child element) is supposed to be applied on blocks (i.e. div'ish not span'ish stuff). Am I confused/mistaken in this regard?
I've googled it but drowned in gazillions of posts on how to align children in a flex container. The closest relative to my issue is here but I don't really understand how it differs from what I'm trying to achieve. Also, it doesn't give me understanding of where my thinking went wrong (undoubtedly it did but I expected it not to).
Is it recommended to always have a non-flex'ish div inside the cell'ish div to encapsulate the text mass inside it? It seems like bad HTML markup.
div.data-row-cell {
display: flex;
padding: 3px;
}
div.data-row-value {
text-align: right;
flex: 1;
}
<div class="data-row">
<div *ngFor="let data of data"
class="data-row-cell data-row-value">
{{data}}
</div>
</div>
In order to understand how flex works, we should do some testing. Therefore I will build some example.
First its important to know that the default behaviour of a flex container direction is set to row. That means that all child elements inside a flex container will be placed next to each other as long as possible.
Also we don't think in left or right anymore when using flexbox. We no think in main axis and cross axis.
The main axis is the direction, the child elements are layed out. So per default it would be from left to right.
The cross axis would then be from top to bottom.
Next it is important to know, that by default the child elements inside the flex container only take as much space as needed.
/* just for some nice looking */
* {
font-family: sans-serif;
box-sizing: border-box;
}
.flex-container {
display: flex;
width: 100%;
padding: 1rem;
background: #666;
}
.flex-item {
padding: 0.5rem;
font-weight: bold;
color: white;
}
.r {
background: red;
}
.g {
background: darkgreen;
}
.b {
background: blue;
}
<div class="flex-container">
<div class="flex-item r">blue</div>
<div class="flex-item g">red</div>
<div class="flex-item b">green</div>
</div>
Since now we know the default behaviour of the flex container and the child elements, lets see what we have to do to make text-alignment work.
One way could be to stretch the child elements, so that the text inside has enough space for alignment.
We could do this with the property flex-grow for the child elements:
/* just for some nice looking */
* {
font-family: sans-serif;
box-sizing: border-box;
}
.flex-container {
display: flex;
width: 100%;
padding: 1rem;
background: #666;
}
.flex-item {
padding: 0.5rem;
font-weight: bold;
color: white;
}
.r {
background: red;
}
.g {
background: darkgreen;
}
.b {
background: blue;
}
/* Updated content */
.flex-item {
flex-grow: 1;
}
.r {
text-align: left;
}
.g {
text-align: center;
}
.b {
text-align: right;
}
<div class="flex-container">
<div class="flex-item r">blue</div>
<div class="flex-item g">red</div>
<div class="flex-item b">green</div>
</div>
So in your case, we could remove the display: flex from the .data-row-cell class and just add some flex-grow: 1
Please see my updated fiddle:
https://jsfiddle.net/7wfm1s0j/
I hope it helps :-)
Normally a when you call the parent display: flex then his children contain a default behavior that means it's default value get flex-direction: row. in a flexbox row element not work text-align property, it's work when you call the flex-direction: column here the solve your problem some example:
**your code**
div.data-row-value {
text-align: right;
flex: 1;
border-color: lightblue;
}
/*my example 1 */
div.data-row-value {
/* text-align: center; */
flex: 1;
border-color: lightblue;
justify-content: flex-end;
}
/*my example 2 */
div.data-row-value {
text-align: right;
flex: 1;
border-color: lightblue;
flex-direction: column;
}
/*my example 3 */
<div *ngFor="let data of data" class="data-row-cell data-row-value">
<div style="width:100%">{{data}}</div>
</div>

Separating two divs

I'm creating a page, at the top of which there is a button (aligned to the right), followed by the main page content in a div.
I've encountered an issue when trying to separate the button and the main content div. The two divs are currently overlapping. I don't imagine this to be a huge issue, but I'd like to clarify what the most accepted way of separating these would be, rather than just messing about with margins etc.
.view-all-container {
display: block;
float: right;
margin-bottom: 40px;
}
.view-all {
background-color: #808080;
color: #fff;
padding: 10px;
}
.main-section {
height: 400px;
background-color: #ebebeb;
}
<div class="view-all-container">
<a class="view-all">View our range of holiday homes</a>
</div>
<div class="main-section">
</div>
I've found that when I add a margin-top: 50px to .main-section the button travels with it, as if it's contained within the same div.
If you are looking for best practices then consider the following:
1) Avoid using float. There are many better ways to get elements where you want them without needing to revert to a complicated process. The biggest problem with float is that it removes your element from the normal DOM flow. https://designshack.net/articles/css/farewell-floats-the-future-of-css-layout/, https://www.webdesignerdepot.com/2014/07/the-secret-to-designing-website-layouts-without-css-floats/
2) If you are navigating, then use the <a> tag. If you are doing something on the same page use a <button> or <input type='button'/> https://davidwalsh.name/html5-buttons
Here is a simple fix for what you want:
.view-all-container {
margin-bottom: 10px;
text-align: right;
}
.view-all {
background-color: #808080;
border: none;
color: #fff;
padding: 10px;
text-align: middle;
}
.main-section {
height: 400px;
background-color: #ebebeb;
padding: 5px;
}
<div class="view-all-container">
<button class="view-all">View our range of holiday homes</button>
</div>
<div class="main-section">
Stuff in the main section
</div>
I removed the float and changed to text-align. The <div> is already display: block so I removed that.
I assumed that your button at the top was to make changes on the active page so I changed the html from an <a> tag to a <button>.
If you don't want to use text-align then try flex-box:
.view-all-container {
display: flex;
justify-content: flex-end;
margin-bottom: 10px;
}
.view-all {
background-color: #808080;
border: none;
color: #fff;
padding: 10px;
}
.main-section {
height: 400px;
background-color: #ebebeb;
padding: 5px;
}
<div class="view-all-container">
<button class="view-all">View our range of holiday homes</button>
</div>
<div class="main-section">
Stuff in the main section
</div>
One of my favorite quotes about using float comes from this article: https://www.sitepoint.com/give-floats-the-flick-in-css-layouts/
If you’re new to CSS layouts, you’d be forgiven for thinking that using CSS floats in imaginative ways is the height of skill. If you have consumed as many CSS layout tutorials as you can find, you might suppose that mastering floats is a rite of passage. You’ll be dazzled by the ingenuity, astounded by the complexity, and you’ll gain a sense of achievement when you finally understand how floats work.
Don’t be fooled. You’re being brainwashed.
You just need to clear the float with clear:right on .main-section
.view-all-container {
display: block;
float: right;
margin-bottom: 40px;
}
.view-all {
background-color: #808080;
color: #fff;
padding: 10px;
}
.main-section {
height: 400px;
background-color: #ebebeb;
clear: right;
}
<div class="view-all-container">
<a class="view-all">View our range of holiday homes</a>
</div>
<div class="main-section">
</div>

Even lines over title and before and after subtitle

I am trying to get a line over my title that lines up evenly with lines before and after my `sub-title
I looked at two references:
Line before and after title over image
CSS technique for a horizontal line with words in the middle
These helped me get started but I am not sure how to get the top line even with the before and after lines without wrapping despite the length of the title or subtitle.
<div class="title">
<h1>Testingtesting</h1>
</div>
<div class="sub-title">
<h1>Testing</h1>
</div>
<style>
#import url(http://fonts.googleapis.com/css?family=Open+Sans:300);
h1 {
width: 20%;
margin: .7em auto;
overflow: hidden;
text-align: center;
font-weight:300;
color: #000;
}
h1:before, h1:after {
content: "";
display: inline-block;
width: 50%;
margin: 0 .1em 0 -55%;
vertical-align: middle;
border-bottom: 1px solid;
}
h1:after {
margin: 0 -55% 0 .1em;
}
span {
display: inline-block;
vertical-align: middle;
}
.title h1 {
border-top: 1px solid black
}
.title h1:before, .title h1:after {
border-bottom: 0px solid;
}
</style>
You should use white-space: wrap; it should work after using it as you have set width on the element on which you are setting this.
For example,
}
.title h1:after {
content:"\A";
white-space: pre;
}
Explanation
In CSS :after is used to generate some content known as a pseudo-element. The "\A" is interpreted as a line break provided that the white space is preserved, hence you need to set white-space: pre. Finally, the element has to be inline, hence display: inline.
I believe I was able to accomplish what you want with the use of flexbox. TL;DR: see snippet below.
First, I nested div.sub-title within div.title in the HTML.
Then, I turned the div.title into a flex container with display: flex, and set the flow direction to column. Adding align-items: center centers the elements within the container.
Next, I targeted the first h1 element, adding a border-top and border-bottom. You can make it however thick you like—I put 4px. If you want to add or reduce the spacing between the borders and the title, adjust the padding.
I then targeted the div.sub-title container. I gave it a position of relative and then offset its position vertically with top: -45px. You may want to adjust this value to get it centered the way you want it. I applied a zero line-height to remove the default value which is pretty tall on a heading. To adjust the spacing between the sub-title and the line on either side, add padding to div.sub-title—I used 20px. Lastly, add a background color that matches your page's background.
While this works, it'll largely depend on how much pre-defined values you're able to use (like padding and background-color).
Another thing to note is when the screen width gets too small, and the subtitle wraps, it'll look really ugly. This is due to the line-height being set to zero. To fix, you can set a min-width on div.title to prevent the entire container from going below a certain width or reset the line-height in div.sub-title at a certain breakpoint with a media query.
.title {
display: flex;
flex-flow: column nowrap;
align-items: center;
min-width: 350px;
}
.title > h1 {
display: inline;
padding: 30px 0;
border-top: 4px solid black;
border-bottom: 4px solid black;
text-align: center;
}
.sub-title {
position: relative;
top: -45px;
/* reset this w/ a media query when screen size gets too small */
line-height: 0px;
padding: 0 20px;
background-color: #fff;
}
<body>
<div class="title">
<h1>Tomorrow Or Something Longer</h1>
<div class="sub-title">
<h1>Today or something</h1>
</div>
</div>
</body>

How to center text vertically with a large font-awesome icon?

Lets say I have a bootstrap button with a font-awesome icon and some text:
<div>
<i class='icon icon-2x icon-camera'></i>
hello world
</div>
How do I make text appear vertically centered?
Text is aligned with the bottom edge of the icon now: http://jsfiddle.net/V7DLm/1/
I just had to do this myself, you need to do it the other way around.
do not play with the vertical-align of your text
play with the vertical align of the font-awesome icon
<div>
<span class="icon icon-2x icon-camera" style=" vertical-align: middle;"></span>
<span class="my-text">hello world</span>
</div>
Of course you could not use inline styles and target it with your own css class. But this works in a copy paste fashion.
See here:
Vertical alignment of text and icon in button
If it were up to me however, I would not use the icon-2x. And simply specify the font-size myself, as in the following
<div class='my-fancy-container'>
<span class='my-icon icon-file-text'></span>
<span class='my-text'>Hello World</span>
</div>
.my-icon {
vertical-align: middle;
font-size: 40px;
}
.my-text {
font-family: "Courier-new";
}
.my-fancy-container {
border: 1px solid #ccc;
border-radius: 6px;
display: inline-block;
margin: 60px;
padding: 10px;
}
for a working example, please see JsFiddle
I use icons next to text 99% of the time so I made the change globally:
.fa-2x {
vertical-align: middle;
}
Add 3x, 4x, etc to the same definition as needed.
After considering all suggested options, the cleanest solution seems to be setting line-height and vertical-align everything:
See Jsfiddle Demo
CSS:
div {
border: 1px solid #ccc;
display: inline-block;
height: 50px;
margin: 60px;
padding: 10px;
}
#text, #ico {
line-height: 50px;
}
#ico {
vertical-align: middle;
}
if things aren't lining up, a simple line-height: inherit; via CSS on specific i.fa elements that are having alignment issues could do the trick simply enough.
You could also feasibly use a global solution, which due to a slightly higher CSS specificity will override FontAwesome's .fa rule which specifies line-height: 1 without requiring !important on the property:
i.fa {
line-height: inherit;
}
Just make sure that the above global solution doesn't cause any other issues in places where you might also use FontAwesome icons.
a flexbox option - font awesome 4.7 and below
FA 4.x Hosted URL - https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css
div {
display: inline-flex; /* make element size relative to content */
align-items: center; /* vertical alignment of items */
line-height: 40px; /* vertically size by height, line-height or padding */
padding: 0px 10px; /* horizontal with padding-l/r */
border: 1px solid #ccc;
}
/* unnecessary styling below, ignore */
body {display: flex;justify-content: center;align-items: center;height: 100vh;}div i {margin-right: 10px;}div {background-color: hsla(0, 0%, 87%, 0.5);}div:hover {background-color: hsla(34, 100%, 52%, 0.5);cursor: pointer;}
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<div>
<i class='fa fa-2x fa-camera'></i>
hello world
</div>
fiddle
http://jsfiddle.net/Hastig/V7DLm/180/
using flex and font awesome 5
FA 5.x Hosted URL - https://use.fontawesome.com/releases/v5.0.8/js/all.js
div {
display: inline-flex; /* make element size relative to content */
align-items: center; /* vertical alignment of items */
padding: 3px 10px; /* horizontal vertical position with padding */
border: 1px solid #ccc;
}
.svg-inline--fa { /* target all FA icons */
padding-right: 10px;
}
.icon-camera .svg-inline--fa { /* target specific icon */
font-size: 50px;
}
/* unnecessary styling below, ignore */
body {display: flex;justify-content: center;align-items: center;height: 100vh; flex-direction: column;}div{margin: 10px 0;}div {background-color: hsla(0, 0%, 87%, 0.5);}div:hover {background-color: hsla(212, 100%, 63%, 1);cursor: pointer;}
<script src="https://use.fontawesome.com/releases/v5.0.8/js/all.js"></script>
<div class="icon-camera">
<i class='fas fa-camera'></i>
hello world
</div>
<div class="icon-clock">
<i class='fas fa-clock'></i>
hello world
</div>
fiddle
https://jsfiddle.net/3bpjvof2/
The simplest way is to set the vertical-align css property to middle
i.fa {
vertical-align: middle;
}
This worked well for me.
i.fa {
line-height: 100%;
}
Try set your icon as height: 100%
You don't need to do anything with the wrapper (say, your button).
This requires Font Awesome 5. Not sure if it works for older FA versions.
.wrap svg {
height: 100%;
}
Note that the icon is actually a svg graphic.
Demo
For those using Bootstrap 4 is simple:
<span class="align-middle"><i class="fas fa-camera"></i></span>
Another option to fine-tune the line height of an icon is by using a percentage of the vertical-align property. Usually, 0% is a the bottom, and 100% at the top, but one could use negative values or more than a hundred to create interesting effects.
.my-element i.fa {
vertical-align: 100%; // top
vertical-align: 50%; // middle
vertical-align: 0%; // bottom
}
I would wrap the text in a so you can target it separately. Now if you float both and left, you can use line-height to control the vertical spacing of the . Setting it to the same height as the (30px) will middle align it. See here.
New Markup:
<div>
<i class='icon icon-2x icon-camera'></i>
<span id="text">hello world</span>
</div>
New CSS:
div {
border: 1px solid #ccc;
height: 30px;
margin: 60px;
padding: 4px;
vertical-align: middle;
}
i{
float: left;
}
#text{
line-height: 30px;
float: left;
}
When using a flexbox, vertical alignment of font awesome icons next to text can be very difficult. I tried margins and padding, but that moved all items. I tried different flex alignments like center, start, baseline, etc, to no avail. The easiest and cleanest way to adjust only the icon was to set it's containing div to position: relative; top: XX; This did the job perfectly.
Well, this question was asked years ago. I think technology has changed quite a bit and browser compatibility is much better. You could use vertical-align but I would consider that some what less scaleable and less reusable. I would recommend a flexbox approach.
Here is the same example the original poster used but with flexbox. It styles a single element. If a button size changes for whatever reason, it will continue to be vertically and horizontally centered.
.button {
border: 1px solid #ccc;
height: 40px;
margin: 60px;
padding: 4px;
display: flex;
justify-content: space-around;
align-items: center;
}
Example: JsFiddle
Simply define vertical-align property for the icon element:
div .icon {
vertical-align: middle;
}
for me, just making the element display gird, and aligning content works perfectly. simply solution.
.yourfontawesome<i>Element{
display: grid;
align-content: center;
}