Dynamically calculate position right with calc() - css

I have been tasked with styling a banner, however the banner itself is a third party tool with severely limited styling options. It's probably easier if I share an example of what I'm working with and then talk through the limitations and what I'm trying to achieve.
body {
margin: 0;
}
.main {
height: 200vh;
min-height: 250px;
width: 1200px;
background: #cdcdcd;
margin: 0 auto;
padding: 20px;
}
<div class="main">
Main website content
</div>
<div class="banner" style="position: fixed; width: 100%; max-width: 600px; height: 80px; background: gray; bottom: 20px; right: 20px; color: white; padding: 20px;">Banner content</div>
Here is a version in Codepen if that's easier.
As you can see, the main website content is centered and is responsive up to (in this case) 1200px, after which the width becomes fixed. The banner needs to always sit at the bottom right, but it should remain within the constraints of the main website content. When the viewport is less than 1200px this solution works fine, the issue I have is of course that on viewports wider than 1200px, the banner breaks out of the constraints of the site.
Generally this wouldn't be an issue, it's easily fixed with calc() and a media query to get the viewport width, but now come the limitations of the banner tool:
I can only add inline CSS via the tool to the element banner, there is no wrapper or inner element I can target
I cannot add CSS to the site that the banner will appear on
I cannot use JavaScript, either on the site or in the banner tool
I can't affect the HTML mark-up in any way (e.g. I can't put the banner inside main
Sorry for the long introduction but hopefully that explains my dilemma. My question is this: is it possible, using CSS calc(), to determine when my viewport is above 1200px and to add (half) that amount to my right offset without affecting the offset when the viewport is less than 1200px, or is there just no solution to this?

Here is one idea that rely on the use if min() in order to define the max-width. You make it either 600px (for bigger screen) or 50% (for small screen) and then adjust the position using translate after centring the element:
body {
margin: 0;
}
.main {
height: 200vh;
min-height: 250px;
width: 1200px;
background: #cdcdcd;
margin: 0 auto;
padding: 20px;
}
* {
box-sizing:border-box;
}
<div class="main">
Main website content
</div>
<div class="banner" style="position: fixed; width: 100%; max-width: min(50%,600px); height: 100px; background: gray; bottom: 20px; right: 0;left:0;margin:auto;transform:translate(50%);border:1px solid red; color: white; padding: 20px;">Banner content</div>
The support is still not good (https://caniuse.com/#feat=mdn-css_types_min) but shortly it will be available on Firefox and all the major browser will be covered.

Related

Single page web without absolute position

is there any way to make single page website without position absolute? Because when I want to variable height of containers, absolute position is little bit awkward. I mean when I insert more content to one container, the other above it should move down. I've tried position static and relative, but it didn't work for me.
Now my css looks like:
<style>
#header {position: absolute; top: 0; left: 0; width: 100%; height: 20%;}
#main {position: absolute; top: 20%; left: 0; width: 100%; height: 80%;}
#about {position: absolute; top: 100%; left: 0; width: 100%; height: 100%;}
#contact {position: absolute; top: 200%; left: 0; width: 100%; height: 50%;}
</style>
<body>
<div id="header">
content....
</div>
<div id="main">
content...
</div>
<div id="about">
long content which is covered with next div, because its "top" atribute settings
</div>
<div id="contact">
div which covers previous one's end
</div>
But when some container needs to be longer, problem is here..
Thanks for any help!
That depends on the style of your website. Of course you can set up anchors and have a one-page scrolling website, but I don't think that answers your question.
My suggestion is to try using absolute positioned elements as containers, and have your actual template inside them.
It would help if you provided some actual code or a specific issue you're having, as it's currently too vague.
I'll provide an answer to what I think you might be asking, though it isn't clear. I hope this isn't too basic.
Ditch the position property altogether.
Just have a div (which is by default 100% width) as your header at the top of your html. The content should be in another div below that.
Divs by default have 100% width, and their height is dependent on the height of their content. They will grow to accommodate taller content. These behaviors are because they have the property display:block .
You've used % which, if I remember correctly, is relative to the parent element. vh (viewport height) is relative to the height of the screen (100vh is the full height of the screen).
I added the background-color just so it's easier to see.
<style>
#header {
background-color: #777;
height: 20vh;
}
#main {
background-color: #999;
height: 80vh;
}
#about {
background-color: #777;
height: 100vh;
}
#contact {
background-color: #999;
height: 50vh;
}
</style>

Why CSS3 is not supporting vertical center (directly)?

One very common question on CSS is how to vertically center an element. With CSS3 being able to do so many special effect, why they are not including the vertically center function into CSS3?
I don't believe it is a difficult function to add if even a beginner developer can make a function to center things with javascript. And with so many hacks for different situations, it is clear that with CSS alone it is possible to center things vertically. So maybe there are other reasons that they decide not to make it a standard property?
That is because how layout is performed with CSS — CSS is predominantly arranging items on the x-axis, like how 100% width works as expected but not 100% height. This is likely due to the possible "calculation/logic loop" that happens as width is dependent on height and vice versa, so one axis must always be prioritized when it comes to calculation.
Extra info by #BoltClock:
The x-axis thing has to do with the natural flow of text in a
document. Remember that the Web started off as a series of pages, so
HTML and CSS were originally built around this fundamental premise -
it has since evolved into an application platform, but the legacy is
still there. Flexbox is the CSS3 way to vertically center boxes - the
only issue is cross-browser support, but since the question is about
CSS3 anyway, that's to be expected.
Similarly, in terms of dictating alignment, horizontal alignment is easy because the width of an element is often implicitly or explicitly stated, like how a block element automatically has a implicit width of 100% unless otherwise stated, allowing for easy calculation of a center position along the horizontal axis.
However, this does not work for the case of vertical alignment, where often than not the vertical dimension is dependent on the amount, length and size of the content. In the case where vertical height is explicitly stated, this can actually be easily done:
by using the CSS flexbox method
The good: standards compliant and very simple, dimension of element of interest does not have to be fixed
The bad: lack of extensive cross-browser support, but appears very promising today
body {
margin: 0;
padding: 0;
}
.box {
background-color: #eee;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
}
.box > .content {
background-color: #333;
color: #eee;
padding: 1em 2em;
}
<div class="box">
<div class="content">I am centered</div>
</div>
by using absolute positioning and CSS transforms
The good: extensive cross-browser support, dimension of element of interest does not have to be fixed
The bad: fuzzy text rendering (occasionally) due to sub-pixel translation
body {
margin: 0;
padding: 0;
}
.box {
background-color: #eee;
position: relatve;
width: 100%;
height: 100vh;
}
.box > .content {
background-color: #333;
color: #eee;
padding: 1em 2em;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
<div class="box">
<div class="content">I am centered</div>
</div>
by using absolute positioning and negative margins
The good: extremely straightforward
The bad: dimension of element of interest MUST be fixed
body {
margin: 0;
padding: 0;
}
.box {
background-color: #eee;
position: relative;
width: 100%;
height: 100vh;
}
.box > .content {
background-color: #333;
color: #eee;
width: 200px;
height: 100px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -50px;
margin-left: -100px;
}
<div class="box">
<div class="content">I am centered</div>
</div>

Footer not on the bottom pf page

I have a lot of space under the footer, and this is something that I would really like to get rid of. For some reason, this space only appears in Google Chrome and not in Firefox.
Heres an image showing it.
http://puu.sh/a6XQI/ec07f0ba31.jpg
What I would like to have happen is my content resize according to the screen size. I am not sure if I can do that because I dont have much content, just a few images.
Any suggestions would be appreciated.
Since you didn't provide any code, I would assume this has to do with the height of you page content being shorther than your window height. Many people who come from a print design background are often perplexed by the concept that a footer doesn't automatically appear at the bottom of a page. The position of dynamically sized elements depends on their content, which as you may come to find out, is very frustrating when a client wants a website built BEFORE providing any content. But I digress.
Assuming the root problem is caused by my former assumption, to achieve what is known as a sticky footer, implement the following to your existing page structions:
jsFiddle: http://jsfiddle.net/63mp6/
HTML
<div class="primary">
<div class="header">
Header Content
</div>
<div class="content">
Main body Content
</div>
<div class="footer">
Footer content
</div>
</div>
CSS
*{
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
html, body {
position: relative;
width: 100%;
height: 100%;
background: #eee;
}
.primary {
position: relative;
width: 80%;
height: 100%;
margin: 0 auto;
}
.header{
min-height: 100px;
min-width: 100%;
background: #aaa;
}
.content {
min-width: 100%;
min-height: 200px;
background: #fff;
}
.footer {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
min-height: 100px;
background: #666;
}
What's happening here is you're resetting default styling to the parent containers, forcing them to 100% height of the window and then telling the footer position about of the default page flow to the bottom of it's parent container. Notice the position: relative; attributes on the primary and html, body definitions. Those set the tone for their child elements to be relative to them instead of the window. Without the position declarations, the child elements would position themselves to the highest element with a relative position, which would be the window itself.

Scaling div width depending on height

I want to have a site that is 100% of the height of the browser at all times, with the width scaling with an aspect ratio when the height is changed.
I can achieve this using the new vh unit: http://jsbin.com/AmAZaDA/3 (resize browser height)
<body>
<div></div>
</body>
html, body {
height: 100%;
width: 100%;
margin: 0;
}
div {
height: 100%;
width: 130vh;
margin: 0 auto;
background: #f0f;
}
However, I worry about fallback for IE8 and Safari, as it this unit is not supported there.
Are there any other CSS only methods of achieving this effect?
I have a solution that works also with IE8 (using Pure CSS 2.1), but not perfectly.
because I need the browser to recalculate things when he get resized, and apparently it doesn't do that unless he has to (and I cant find a way to make him think he has to), so you will have to refresh the page after resizing.
as far as I know, the only element that can scale reserving his ratio is an <img>, so we will use the <img> to our advantage.
SO, we are going to use an image with the ratio that we want (using the services of placehold.it), lets say we want a 13X10 ratio (like in your example), so we'll use <img src="http://placehold.it/13x10" />.
that image will have a fixed height of 100% the body, and now the width of the image scales with respect to the ratio. so the width of the image is 130% height of the body.
that image is enclosed within a div, and that div has inline-block display, so he takes exactly the size of his content. witch is the size you want.
we remove the image from the display by using visibility: hidden; (not display:none; because we need the image to take the space), and we create another absolute div, that will hold the actual content, that will be right above the image (100% width and 100% height of the common container).
That works perfectly when you first initiate the page, but when you resize the page, the browser doesn't always measure the right width and height again, so you'll need to refresh to make that happened.
Here is the complete HTML:
<div class="Scalable">
<img class="Scaler" src="http://placehold.it/13x10" />
<div class="Content"></div>
</div>
and this simple CSS:
html, body, .Content
{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body
{
text-align: center;
}
.Scalable
{
position: relative;
display: inline-block;
height: 100%;
}
.Scaler
{
width: auto;
height: 100%;
margin-bottom: -5px;
visibility: hidden;
}
.Content
{
position: absolute;
top: 0;
background-color: black;
}
Here's a Fiddle (don't forget to refresh after resizing)
I recommend you to copy this code to your local machine and try it there rather then within the fiddle.
In this similar SO question a CSS technique was found and explained on this blog entry that allows an element to adjust its height depending on its width. Here is a repost of the code:
HTML:
<div id="container">
<div id="dummy"></div>
<div id="element">
some text
</div>
</div>
CSS:
#container {
display: inline-block;
position: relative;
width: 50%;
}
#dummy {
margin-top: 75%; /* 4:3 aspect ratio */
}
#element {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: silver /* show me! */
}
Demo Here
If this is sufficient for you, I'd recommend this technique. However, I'm unaware if the technique can be adapted to handle scenarios where you must have an element adjust its width depending on its height.
You can do it with the help of padding on a parent item, because relative padding (even height-wise) is based on the width of the element.
CSS:
.imageContainer {
position: relative;
width: 25%;
padding-bottom: 25%;
float: left;
height: 0;
}
img {
width: 100%;
height: 100%;
position: absolute;
left: 0;
}

CSS Responsive Fluid Square (with scrollable content)

So I'm trying to build a pure CSS responsive square (well actually I'm trying to build a circle but that's easy once I've got the square.)
In other words:
I want a div that has a height that is a percentage of the body and a width that is equal to that (or vice versa).
The div also needs to have another div inside it which can contain content and overflow: auto.
Lastly, the div can never exceed the height (or width) of the body or viewport.
So far, I have got some solutions working partially (i.e. in portrait but not landscape) using a 1px transparent .gif as an img to fill out a wrapper div. Not ideal semantics but I don't see how this can be done without it.
<div class="wrap">
<img src="http://www.neurillion.com/p/35/static/media/images/1x1t.gif" />
<main>
<div class="content">
<h2>Title</h2>
<p> Lorem... etc. </p>
</div>
</main>
</div>
Here are my CSS solutions and what is wrong with them:
This works except it exceeds the height of the body in landscape (max-height in any of the elements does not solve this):
.wrap {
background: blue;
margin: 10% auto;
width: 70%;
position:relative;
text-align:center;
}
.wrap img {
border: 1px solid black;
height: auto;
width: 100%;
}
main {
background: red;
display: block;
border-radius:50%;
height: 100%;
width: 100%;
position: absolute;
top:0
}
main div {
background: green;
overflow: auto;
display:inline-block;
height:70%;
width: 70%;
margin-top:15%;
}
Codepen
Next I added a landscape media query to swap around the height and width values. Same problem.
#media(orientation:landscape) {
.wrap {
margin: auto 10%;
height: 70%;
width: auto;
}
}
Codepen
At this point I started looking into .wrap's parent elements , namely the body and html. (Resource on the difference between them.) I added height and max-height: 100% to both of them, but no joy. I've also tried adding another div container as I thought it might be easier to control the height, but that doesn't seem to be doing much either.
And now I'm pretty much out of options. I'm fairly sure the solution is something to do with the html and body elements and the way they are so eager to expand vertically but I'm not really sure how else to stop them doing so.
Any help much appreciated.
You can use vw, vh and vmin to scale the square:
Demo: http://jsfiddle.net/r9VQs/
CSS (changed part only):
.wrap {
background: blue;
margin: 0 auto;
max-width: 90vh;
max-height: 90vh;
position:relative;
text-align:center;
}
You can also use vmin (which gives better results but is less well supported) and forego the image:
Demo: http://jsfiddle.net/r9VQs/2/
CSS:
.wrap {
background: blue;
margin: 0 auto;
width: 90vmin;
height: 90vmin;
position:relative;
text-align:center;
}
vh, vw and vmin are units equivalent to 1% of their respective viewport dimensions (vh is viewport-height, vw is viewport-width and vmin is whichever has a smaller value).
Please see http://caniuse.com/#feat=viewport-units for browser support.

Resources