CSS3 calc() doesn't work with position fixed/absolute - css

Does anyone know a workaround for this?
I'm trying to calculate width of a div :
#container {
position: fixed;
top: 0;
left: 0;
z-index: 9;
display: none;
background: #fff;
width: calc(100% - 1em);
padding: .5em;
}

EDIT 2:
This is the version for Webkit browsers (as asked in comments), tested with the latest release of Chrome, and fully working for me: http://jsfiddle.net/HvVst/1/
used -webkit-calc() instead of calc().
EDIT: Then you have to subtract the 1px borders to the 0.5em padding, like this:
http://jsfiddle.net/HvVst/
HTML:
<div id="banner">
FIXED HEADER
</div>
<div id="main">
normal div
<br/>
Sample Text 1
<br/>
Sample Text 2
<br/>
Sample Text 3
<br/>
Sample Text 4
<br/>
Sample Text 5
<br/>
Sample Text 6
<br/>
Sample Text 7
<br/>
Sample Text 8
</div>
CSS:
#banner{
position: fixed;
top: 0;
left: 0;
z-index: 9;
background: #fff;
width: calc(100% - 1em);
padding: calc(0.5em - 1px); /* <-- THIS ONE !!*/
border: 1px solid red;
height: 50px;
}
#main{
margin-top: calc(50px + 1em);
border: 1px solid blue;
height: 500px;
}
It works with position fixed/absolute, but (if no relative parents specified for absolute, and always for fixed) it refers to the window width, not to the container width.
(100% - 1em) = 100% of the window excluding the scrollbar...
what are you trying to achieve ?
If you want position absolute in the parent's boundaries, set the parent to position:relative...

Related

How to properly position inclined text of different sizes into a specific zone?

I am trying to position a piece of text (fixed font and max length of 6) on top of an image. The image will be of a product and I have to show how customer's text would look onto that product.
The tricks are :
the text is inclined
needs to be responsive (mobile screens are most important for now)
This is what I have so far jsfiddle here, but I reckon some math has to be done on the positioning of the sample text (using the css calc() function)
Borders
(these will not stay and are there for better understanding positions)
black borders show the image's border and where the text needs to fit
red border is the container of the image and the overlayed text
green border it the container of the overlayed text
#sample-container {
position: relative;
width: 100%;
z-index: 1;
border-style: solid;
border-color: red;
}
#sample-image {
position: relative;
width: 100%;
height: auto;
z-index: 1;
}
#sample-text {
z-index: 2;
position: absolute;
text-align: center;
top: 35%;
right: 59%;
text-align: right;
color: gray;
font-size: 5vw;
transform: rotate(-16deg);
border-style: solid;
border-color: green;
}
#font-face {
font-family: "Verdana";
}
<div id="sample-container">
<img id="sample-image" src="https://i.ibb.co/R9qKGMb/sample-image.png">
<div id="sample-text">SAMPLE</div>
</div>
The problems:
text of different lengths messes up my positioning
(extra : if this is shown on a desktop website, where the content is centered on the page and there are margins on left and right, for better readability I suppose, then using measurements relative to the viewport breaks the positioning on resizing; the sample code does not show this problem yet, as it allows the image to be full page width)
One idea is to make the text container to have a width equal to 0 and rely on overflow. Doing so you will always position the same element (width/height) whataver the text inside:
#sample-text-configuration-container {
position: relative;
}
#sample-container {
position: relative;
width: 100%;
z-index: 1;
border-style:solid;
border-color:red;
}
#sample-image {
position: relative;
width: 100%;
height: auto;
z-index: 1;
}
#sample-text {
z-index: 2;
position: absolute;
text-align: center;
top:39%;
right:80%;
text-align:right;
color: gray;
font-size:5vw;
transform: rotate(-16deg);
width:0;
}
#font-face {
font-family: "Verdana";
}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<div id="sample-text-configuration-container">
<span>Custom text:</span>
<input
type="text"
maxlength=6
value="SAMPLE"
onfocus="this.value=''"
oninput="document.getElementById('sample-text').innerHTML = this.value;"/>
<br/>
<span>Text top position:</span>
<input
type="text"
value="39%"
oninput="document.getElementById('sample-text').style.top = this.value;"/>
<br/>
<span>Text right position:</span>
<input
type="text"
value="80%"
onkeydown="document.getElementById('sample-text').style.left = this.value;"/>
<br/>
<span>Text size:</span>
<input
type="text"
value="5vw"
oninput="document.getElementById('sample-text').style.fontSize = this.value;"/>
<div id="sample-container">
<img id="sample-image" src="https://i.ibb.co/R9qKGMb/sample-image.png">
<div id="sample-text">SAMPLE</div>
</div>

How to position an element to the LEFT of an other element?

What is the idiomatic way to position an element (X) to the left of an other element (inline-box 2), independent of its size, using standard CSS & HTML?
It is okay if it appears over other elements.
I have found a solution: to position an element to the left of another one, no matter their sizes, make it its child, and then absolute-position it right: 100%.
100% means the width of its parent, so 100% from the right will put it just left of it!
Using left: -100% wouldn't work, because it means: offset the left of the element left of the parent by the parent's width, however we want to offset by the width of the child element, itself.
CSS-only demo:
/* The important parts */
#box2 {
position: relative;
}
#x {
position: absolute;
right: calc(100% + 5px);
top: -1px;
}
/* Just styling */
#box1, #box2 {
border: 1px solid blue;
width: 200px;
margin-right: 10px;
display: inline-block;
}
#x {
border: 1px solid orangered;
width: 100px;
height: 150px;
}
<div id="container">
<div id="box1">box1</div>
<div id="box2">box2
<div id="x">X</div>
</div>
</div>

CSS calc() in Safari with float values

I have a problem with the CSS function calc in Safari.
I have following code: https://jsfiddle.net/0Lugw0zq/1/
#parent {
position: absolute;
height: 32px;
width: 120.77px;
background-color: red;
border: 5px solid black;
}
#child {
position: absolute;
height: 32px;
left: 12px;
width: calc(100% - 12px);
background-color: black;
}
<div id="parent">
<div id="child"></div>
</div>
In Chrome / Firefox you will see a black box and smaller red box in its left, while in Safari there will be an additional thin red line in the right part of the box.
Notice how the parent container's width has a float value (120.77px). The child container's width is calculated with calc(100% - 12px) what results in 108px instead of 108.77px in Safari - obviously due to integer parsing.
How can I prevent Safari from showing this thin line?

Square with rounded corners and indented curved border

I was wondering if it is possible to make a square with round corners and a indented border in pure CSS.
Currently I have this:
#custom-square {
position: relative;
display: block;
width: 75px;
height: 75px;
border: 2px solid #8A6EF1;
border-radius: 10px;
background-color: white;
}
Considering the hassle and amount of code needed to align double curves with CSS, SVG seems way more appropriate. A few other reasons to go for svg here are :
control of the path (color, width, curve...)
control the fill with a plain color, gradient or image
less code
you can display it over a non plain background (gradient or image)
maintain the boundaries of the shape for user interactions (hover, click...)
Here is a basic example using an inline svg with a path element.
The curves are drawn with Cubic Bezier curves :
svg{width:30%;}
<svg viewbox="0 0 10 10">
<path d="M1.5 0.5 Q5 1 8.5 0.5 Q9.5 0.5 9.5 1.5 Q9 5 9.5 8.5 Q9.5 9.5 8.5 9.5 Q5 9 1.5 9.5 Q0.5 9.5 0.5 8.5 Q1 5 0.5 1.5 Q0.5 0.5 1.5 0.5z"
fill="none" stroke-width="0.2" stroke="#8A6FF2" />
</svg>
Another pure CSS approach for creating this border would be to make use of border-image property. All that is required is create an image with the required border shape and set it to an element using the border-image-source property.
.shape.large {
height: 300px;
width: 300px;
border-image-source: url(http://i.stack.imgur.com/Qkh6A.png);
border-image-width: 34px; /* the width of the border portions in the image - refer to image at the end of the answer for the exact portion details*/
border-image-slice: 34; /* equal to border-image-width */
border-width: 34px; /* equal to border-image-width */
}
.shape.small {
height: 100px;
width: 100px;
border-image-source: url(http://i.stack.imgur.com/Mra4B.png);
border-image-width: 14px;
border-image-slice: 14;
border-width: 14px;
}
.shape.small.fill {
background: aliceblue content-box;
border-image-source: url(http://i.stack.imgur.com/Ovj03.png);
border-width: 14px;
}
/* Just for demo */
body {
background: url(http://lorempixel.com/800/800/abstract/2);
}
.shape.small {
float: left;
}
.shape.large {
clear: both;
}
<div class='shape small'>Some content</div>
<div class='shape small fill'>Some content</div>
<div class='shape large'>Some content</div>
At present this method is definitely not much advantageous compared to SVG but it is an option and in my opinion is better than the other CSS only approaches that are possible.
The advantages of this approach are:
Very minimal and low complexity code.
Better control over the curves and their radii (like with SVG) because the image with the required border curvature can be created separately.
Can be placed on top of an image or a gradient background.
Can be made to degrade gracefully (into a solid square border) in browser's that don't support it.
The drawbacks are:
The container is still a square and so hover effects will not be restricted to the boundaries of the shape unlike with SVG.
Adding solid color fill to the shape is possible (by using a filled version of the image) but adding a gradient or image fill is tricky because borders are still blocks (that is, there are transparent areas on either side of the curves).
The output is responsive but as dimensions increase or decrease beyond a threshold, the shape starts to look a bit compressed or stretched. So, this is more suited for break-point based design.
The browser support is not bad but is not great either. It works in Chrome, Firefox, Safari, Opera and IE11+.
Calculation of Border Image Width:
The width or height of border area (which becomes the border-image-width) is nothing but the width of the portion highlighted in the below image.
This draft mock up is as close as i could get it to pure CSS, but still requires a nested div. You would need to tweak the sizing / radius for the before / after circles.
Pen
div {
position: absolute;
top: 100px;
left: 100px;
width: 100px;
height: 100px;
border: 4px solid purple;
border-radius: 30px;
//overflow: hidden;
box-sizing: border-box;
&:before {
position: absolute;
top: -4px;
left: -94px;
content: ' ';
width: 100px;
height: 100px;
border: 4px solid purple;
border-radius: 50px;
box-sizing: border-box;
background-color: white;
clip: rect(0px, 100px, 100px, 90px);
}
&:after {
position: absolute;
top: -4px;
right: -94px;
content: ' ';
width: 100px;
height: 100px;
border: 4px solid purple;
border-radius: 50px;
box-sizing: border-box;
background-color: white;
clip: rect(0px, 10px, 100px, 0px);
}
}
div > div {
position: absolute;
top: -4px;
left: -4px;
transform: rotate(90deg);
border-color: transparent;
}
SVG is probably the way to go here, but here's a pretty close approximation in pure CSS. It could be made even better by increasing the size of the outer circles.
#middle {
width: 96px;
height: 96px;
border-radius: 10px;
background-color: green;
border: 2px solid #8A6EF1;
}
.outside {
width: 100px;
height: 100px;
position: relative;
overflow: hidden;
margin: 0;
padding: 0;
}
.cutout {
width: 96px;
height: 96px;
border-radius: 50%;
background-color: white;
border: 2px solid #8A6EF1;
}
#top {
top: -100px;
height: 10px;
}
#right {
top: -110px;
left: 90px;
width: 10px;
}
#bottom {
top: -120px;
height: 10px;
}
#left {
top: -220px;
width: 10px;
}
#top > .cutout {
margin-top: -90px;
}
#left > .cutout {
margin-left: -90px;
}
<div id="wrapper">
<div id="middle">
</div>
<div id="top" class="outside">
<div class="cutout">
</div>
</div>
<div id="right" class="outside">
<div class="cutout">
</div>
</div>
<div id="bottom" class="outside">
<div class="cutout">
</div>
</div>
<div id="left" class="outside">
<div class="cutout">
</div>
</div>
</div>

Force text inside CSS triangle to stay in one line

I'm toying around with a triangle inside a div and want to place text inside that triangle. So far everything works as expected - only problem is the text gets warped at space - if there is no space between the words it all fits:
<div style="position:absolute;z-index: 1;width: 0;height: 0;border-style: solid;border-width: 125px 125px 0 0;border-color: #1abc9c transparent transparent transparent;">
<div style="top: -100px; left: 10px; right:0px; position:absolute;">
<p>11 one</p>
</div>
</div>
I've tried making the text 1px and it still warps so it's obviously not a lack of space issue. Any ideas what's the problem?
Why is this happening?
Firstly, let's clean up the HTML by separating the CSS.
The HTML
<div class="outerParent">
<div class="innerParent">
<p>11 one</p>
</div>
</div>
The CSS
.outerParent {
position: absolute;
z-index: 1;
width: 0;
height: 0;
border-style: solid;
border-width: 125px 125px 0 0;
border-color: #1abc9c transparent transparent transparent;
}
.innerParent {
top: -100px;
left: 10px;
right: 0px;
position: absolute;
}
Better! Now, the first thing we see is that .outerParent has width: 0. This means that it's child .innerParent has no width. When text hits the edge of its container (which happens immediately because of width: 0 on .outerParent), it will wrap any whitespace, and this is controlled by the white-space property:
The white-space CSS property is used to to describe how white spaces inside the element is handled.
How do I prevent this from happening?
The default white-space value is "normal" and this will wrap. Use the white-space property and set it to "nowrap":
white-space: nowrap;
The other option is to force the paragraph element to push outside of it's parent by giving it a width:
width: 50px;
Working Example
.outerParent {
position: absolute;
z-index: 1;
width: 0;
height: 0;
border-style: solid;
border-width: 125px 125px 0 0;
border-color: #1abc9c transparent transparent transparent;
}
.innerParent {
top: -100px;
left: 10px;
right: 0px;
position: absolute;
}
p {
white-space: nowrap;
}
<div class="outerParent">
<div class="innerParent">
<p>11 one</p>
</div>
</div>

Resources