A circle element next to a fluid rounded element - javascript

Is the following layout possible with CSS? If not, is there a better solution than my current JS solution? See the fiddle for a complete example.
+--------------------+
| |
| |
| |
| |
| |
| |
| |
| |
| |
|--------------------+
|+----+ +----------+| container height in percentage, e.g. 20% of window
|| 1 | | 2 || button 1: a circle based on container height
|+----+ +----------+| button 2: fill available space and fully round corners
+--------------------+
The basic issue is that the first element needs to be a circle, i.e. a rounded square, based on the height of the container. And the second element should fill the rest of the space with the same border-radius.
Following is how I solved it with JS, but it does not seem to be too reliable on mobile devices. And the project is basically mobile-only. Also, if the layout is too dependent on JS, it will cause other trouble when doing fancy transitions etc. with CSS.
Fiddle: http://jsfiddle.net/n52x1ws1/3/
$(document).ready(function(){
var height = $(".device-fluid").find(".btn-circle").height();
var borderRadius = height / 2;
$(".device-fluid").find(".btn-circle").css("width", height);
$(".device-fluid").find(".btn-circle").css("border-radius", borderRadius);
var fluidWidth = $(".device-fluid").find(".container").width() - height - 15;
$(".device-fluid").find(".btn-fluid").css("width", fluidWidth);
$(".device-fluid").find(".btn-fluid").css("border-radius", borderRadius);
});
* {
box-sizing: border-box;
font-family: sans-serif;
}
.device {
display: inline-block;
position: relative;
width: 320px;
height: 480px;
border: 2px solid #ccc;
margin: 30px;
text-align: center;
}
.label {
margin-top: 30px;
}
.container {
position: absolute;
bottom: 0;
width: 100%;
height: 20%;
padding: 15px;
background: #f7f7f7;
}
.btn {
height: 100%;
}
.btn-circle {
float: left;
}
.btn-fluid {
float: right;
}
.device-fixed .btn-circle {
width: 66px; /* easy since we know the height */
border-radius: 33px;
background: #2ecc71;
}
.device-fixed .btn-fluid {
width: 205px; /* available space minus a 15px margin */
border-radius: 33px;
background: #27ae60;
}
.device-fluid .btn-circle {
width: 20%; /* this needs to be equal to the height */
border-radius: 50%;
background: #2ecc71;
}
.device-fluid .btn-fluid {
width: 75%; /* this needs to fill the rest of the available space minus a 15px margin */
border-radius: 50%;
background: #27ae60;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="device device-fixed">
<div class="label">fixed</div>
<div class="container">
<div class="btn btn-circle"></div>
<div class="btn btn-fluid"></div>
</div>
</div>
<div class="device device-fluid">
<div class="label">fluid with JS</div>
<div class="container">
<div class="btn btn-circle"></div>
<div class="btn btn-fluid"></div>
</div>
</div>

I'm not exactly sure what you mean by
container height in percentage, e.g. 20% of window
If that means that the height of the container is determined by the size of the viewport you can use the viewport units. 1vh equals 1% of the viewport height.
.container {
height: 20vh;
}
You can then easily make a circle based on this height:
.btn-circle{
height: 20vh;
width: 20vh;
border-radius: 10vh;
}
The next div should fill the available space
.btn-fluid{
height: 20vh;
width: calc(100vw - 20vh); /*100% of the viewport width minus the space for the square*/
border-radius: 10vh;
}
It looks like this in a fiddle.

Related

css triangle based on page height

Currently I have the situation as shown below in the snippet.
But now I want a triangle that is the same on every page. No matter how long the page is. So for example if the page is really long, then the triangle will at one point go out of the screen and there will be no more green background. (as shown here)
But the most important thing is that on every page the triangle/angle will be the same. How to do this?
$(document).ready(function() {
function waitForElement(elementPath, callBack) {
window.setTimeout(function() {
if ($(elementPath).length) {
callBack(elementPath, $(elementPath));
} else {
waitForElement(elementPath, callBack);
}
}, 300)
}
waitForElement("#leftdiv", function() {
// Initial background height set to be equal to leftdiv
$('#rightdiv').height($('#leftdiv').height());
// Initial triangle height set to be equal to leftdiv
$('#triangle').css('border-top', $('#leftdiv').height() + 'px solid transparent');
});
// When window resizes
$(window).resize(function() {
// Change height of background
$('#rightdiv').height($('#leftdiv').height());
// Change height of white triangle
$('#triangle').css('border-top', $('#leftdiv').height() + 'px solid transparent');
});
});
.container-general {
float: left;
position: relative;
background-color: black;
height: 500px;
width: 70%;
}
.background-general {
float: right;
position: relative;
/*height is set in javascript*/
width: 30%;
background-color: green;
}
#triangle {
position: absolute;
height: 0;
width: 0;
bottom: 0;
left: -1px;
border-left: 10vw solid white;
border-right: 0px solid transparent;
/*border-top is set in javascript*/
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container-general" id="leftdiv">
</div>
<div class="background-general" id="rightdiv">
<div id="triangle"></div>
</div>
You don't need JavaScript and jQuery at all for this, as long as you are willing to make minor changes to your markup:
Step 1: Update your markup
Wrap both your .container-general and .background-general with a common parent element
Use display: flex; overflow: hidden; on the parent. This has the effect of stretching the shorter background element to full height of .container-general
Step 2: Determine the fixed angle you want and set aspect ratio
Important note: If you want to keep the angle constant, you will need to know what angle you want. That will require one important trick: you want to keep .background-general the same aspect ratio in all cases, so the angle stays constant. Let's say you want it to be 60° (i.e. Math.Pi / 3): with some math, that means that the height of the .background-general should be this ratio relative to the width:
containerHeightRatioToWidth = Math.tan(Math.PI / 3) = 1.732052602783882...
There is a trick to preserve the aspect ratio: you simply set the padding-bottom of the background element. In this case, you want it to be padding-bottom: 173%); (we don't need absolute precision so we can drop the decimal points).
Here's a handy table on the height (in CSS percentages) you can use:
30deg: padding-bottom: 57%:
45deg: padding-bottom: 100%:
60deg: padding-bottom: 173%:
You can also precalculate the percentage in your browser console by pasting this:
var desiredAngleInDegrees = 60;
Math.tan(Math.PI * desiredAngleInDegrees / 180) * 100
The markup is structured as follows:
└─┬.wrapper
├──.container-general
└─┬.background-general
└─┬.background-general__background
├─::before (triangle)
└─::after (remaining fill)
To achieve the triangle effect, you have two approaches:
Step 3A: Use clip-path to trim the background element to look like a triangle
clip-path is very widely supported by modern browsers, with a notable exception for IE11 and Edge :/ This should do the trick: clip-path: polygon(100% 0, 0 0, 100% 100%);
.wrapper {
display: flex;
overflow: hidden;
}
.container-general {
background-color: black;
height: 500px;
width: 70%;
}
.background-general {
position: relative;
width: 30%;
background-color: green;
overflow: hidden;
}
.background-general__background {
position: absolute;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
/* Triangle */
.background-general__background::before {
flex-grow: 0;
content: '';
display: block;
width: 100%;
padding-bottom: 173%;
background-color: white;
clip-path: polygon(0 100%, 0 0, 100% 100%);
}
/* Extra fill */
.background-general__background::after {
flex-grow: 1;
content: '';
display: block;
background-color: white;
/* Needed to fix subpixel rendering */
margin-top: -1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div class="container-general" id="leftdiv">
</div>
<div class="background-general" id="rightdiv">
<div class="background-general__background"></div>
</div>
</div>
Step 3B: Use an inline SVG as background image
For the greater browser compatibility, use an inline encoded SVG and stretch it to 100% width and 100% height of the parent.
We can create a simple 10×10px SVG of the following markup:
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 10 10">
<path fill="green" d="M0,0 L10,0 L10,10 z"></path>
</svg>
Note: The preserveAspectRatio="none" is required so that we can freely stretch the SVG beyond its usual aspect ratio. For more information of how the <path>'s d attribute works, see this article: The SVG path Syntax: An Illustrated Guide
Then, all you need is to stuff this short SVG markup as data:image/svg+xml for the background image of the background container, i.e.:
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 10 10"><path fill="green" d="M0,0 L10,0 L10,10 z"></path></svg>');
See example below:
.wrapper {
display: flex;
overflow: hidden;
}
.container-general {
background-color: black;
height: 500px;
width: 70%;
}
.background-general {
position: relative;
width: 30%;
background-color: green;
overflow: hidden;
}
.background-general__background {
position: absolute;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
/* Triangle */
.background-general__background::before {
content: '';
display: block;
flex-grow: 0;
width: 100%;
padding-bottom: 173%;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none" viewBox="0 0 10 10"><path fill="white" d="M0,0 L0,10 L10,10 z"></path></svg>');
background-size: 100% 100%;
}
/* Extra fill */
.background-general__background::after {
flex-grow: 1;
content: '';
display: block;
background-color: white;
/* Needed to fix subpixel rendering */
margin-top: -1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<div class="container-general" id="leftdiv">
</div>
<div class="background-general" id="rightdiv">
<div class="background-general__background"></div>
</div>
</div>
A simple "border triangle" bind to vw units might do:
body {
min-height: 2000px;
}
#triangle {
position: absolute;
top: 0px;
right: 0px;
border-top: 100vw solid #ff0000; /* The height of the triangle */
border-left: 30vw solid transparent; /* The width of the triangle */
}
<div id="triangle"></div>
A fiddle to play with.

Create a div with aspect ratio 1:1 knowing only its height in percentage

I was wondering if you can help me with this.
I have a div (in white) where I need to put two circular buttons (in green) on the borders. Everything should be done with CSS.
It should look like this:
Screenshot
Now, the thing is that I don't know the size of the white div, and I won't know it at the time of creation, because it will get added to the DOM afterwards. All I know is that the white div has a percentage width and height relative to its future parent. So, at the time of creation, since it's not yet added, any calls to width(), height() or its css values won't work.
I've seen all those snippets that tell you how to make a div with a fixed aspect ratio. I need this now, I need the button to be 1:1, but all I know about the dimensions, is that it has to be 100% of the height of the white div (and therefore, its width should be equal as its height). All the examples I've seen assume that you know the width and to make the height keep the ratio. In my case, what I know is the height (100%) and I want the width to adapt.
I have no idea how to achieve this.
This is my snippet:
body{
background-color: #DCDCDC;
}
.container {
width: 50%;
height: 7%;
background: white;
border-radius: 20px;
position: absolute;
}
.arrow {
background: green;
border-radius: 20px;
height: 100%;
position: absolute;
}
.arrow:after{
content: "";
display: block;
padding-right: 100%;
}
.arrow:last-child {
right: 0;
}
<div class="container">
<div class="arrow"></div>
<div class="arrow"></div>
</div>
https://jsfiddle.net/7bxecL9m/
If you know how can I do this without entering any fixed value (jQuery use is of course valid), I'd really appreciate it.
Thanks.
There are many variables here:
Since container's height is % and circle radius is px units, one is static and the other one will resize.
The only way to preserve 1:1 with just html/css, considering the container's height % will resize circle's height as well, would be to isolate circle's div width & height to something static like px units.
Now, since you said no fixed dimensions, the only thing I can think of is to comment .arrow's 100% height, to prevent resizing other than 1:1, and nesting a div inside .arrow to restrain 1:1 with static units (ideally impacting .arrow directly would be less code but if you don't want/can't set them on that element, maybe you consider this).
If you want the circle to remain circular as the content expands, you need to dynamically adjust the height to match the width. You could use Javascript to achieve this, but your border-radius is tied to container's in px static units, since container will always be bigger something like border-radius: 50% wouldn't work for both, 50% radius of circle would never match 50% of container's (that is, if you care about radius alignment).
body {
background-color: #DCDCDC;
}
body,
html {
height: 100%;
}
.container {
width: 50%;
height: 37%;
background: white;
border-radius: 20px;
position: relative;
}
.arrow {
background: green;
border-radius: 20px;
/*height: 100%;*/
position: absolute;
overflow: hidden;
}
.bLimit {
height: 40px;
width: 40px;
line-height: 40px;
}
.arrow:after {
content: "";
display: block;
padding-right: 100%;
}
.arrow:last-child {
right: 0;
}
<div class="container">
<div class="arrow">
<div class="bLimit">button overflow</div>
</div>
<div class="arrow">
<div class="bLimit">button</div>
</div>
</div>
Why not doing a fixed width in percent for your arrow :
.arrow {
background: green;
border-radius: 20px;
height: 100%;
position: absolute;
width: 10%;
}
body{
background-color: #DCDCDC;
}
.container {
width: 50%;
height: 7%;
background: white;
border-radius: 20px;
position: absolute;
}
.container:after,.container:before{
content: " ";
display: block;
padding: 4%;
z-index: 999;
top: 0;
position:absolute;
background: green;
border-radius: 50%;
}
.container:before {
left: 0;
}
.container:after{
right: 0;
}
<div class="container">
</div>
You can achieve using before and after CSS pseudo selectors. You check this Example.
There is a posibility to get this result using a image (that won't show) of the required ratio.
In this case, the ratio is 1:1 so we will use an image of 50px (but it can be any size)
.container {
width: 300px;
height: 20px;
border: solid 1px blue;
margin: 40px;
position: relative;
}
.container:nth-child(2) {
height: 40px;
}
.container:nth-child(3) {
height: 60px;
}
.arrow {
height: 100%;
background-color: red;
opacity: 0.5;
position: absolute;
border-radius: 50%;
transform: translateX(-50%);
}
.arrow:last-child {
right: 0px;
transform: translateX(50%);
}
img {
height: 100%;
opacity: 0;
}
<div class="container">
<div class="arrow">
<img src="https://placehold.it/50x50">
</div>
<div class="arrow">
<img src="https://placehold.it/50x50">
</div>
</div>
<div class="container">
<div class="arrow">
<img src="https://placehold.it/50x50">
</div>
<div class="arrow">
<img src="https://placehold.it/50x50">
</div>
</div>
<div class="container">
<div class="arrow">
<img src="https://placehold.it/50x50">
</div>
<div class="arrow">
<img src="https://placehold.it/50x50">
</div>
</div>

How do you make a div only extend in one direction when the outer container size increases?

I'm trying to make a a page container with a navigation bar on the left (inside of the container). When the outer page is wider than the container, I would like just the navigation bar to extend left up to a certain size while the rest of the container's contents to remain the same and stay in the middle of the outer page.
To illustrate my idea, here are the before and after images, with black representing the outer page, blue the page container, pink the leftnav, and green the rest of the container.
Here is also the general structure of the code I am writing. The jsfiddle link includes some css for detail.
<div id="page">
<div id="container">
<div id="leftCol">
LEFT
</div>
<div id="rightCol">
RIGHT
</div>
</div>
https://jsfiddle.net/6L1zrj6e/1/
Currently, my container has a fixed width and automatic margins so as to center it. Is what I am trying to achieve even possible with the current layout? Would I need to move the leftnav div outside of the container?
Here's a pure css solution: fiddle
This is a trick I learned here: here
where you have to put the float first, then make the div respect it by creating a new block formatting context, then the div will expand to the remaining space. Throw in a couple min/max widths to conform it and a wrapper with min/max widths as well and it falls into place. The html background makes the body background not extend past the body as it normally would. Another little trick.
<div class="wrap">
<main></main>
<nav></nav>
</div>
html {
background: white;
}
body {
background: purple;
padding: 0;
margin: 0;
}
.wrap {
margin: 0 auto;
max-width: 1080px;
min-width: 920px;
}
nav {
overflow: auto; /* force a new context to respect float */
background: red;
height: 300px;
min-width: 200px;
max-width: 360px;
}
main {
float: right;
background: green;
height: 300px;
width: 720px;
}
You can try the following: Full screen example
jsFiddle
HTML:
(Took leftCol out of container)
<div id="page">
<div id="leftCol">
LEFT
</div>
<div id="container">
<div id="rightCol">
RIGHT
</div>
</div>
</div>
JS: (Update the width on page resize and on load)
$(window).on('resize', function(){
var containerWidth = 980;
var pageWidth = $(window).width();
var tempW = Math.max(0, pageWidth-containerWidth) / 2;
tempW += 200;
var w = Math.min(tempW, 360); // 360 = max width
var l = Math.max(0, tempW - w);
$('#leftCol').css({'width': w+'px', 'left': l+'px'});
}).resize();
CSS: (Removed floats, using absolute position for leftCol)
#page{
background-color: purple;
position:relative;
}
#container {
background-color: blue;
width: 980px;
height: 300px;
margin: 0 auto;
}
#leftCol {
position:absolute;
top: 0;
left: 0;
background-color: red;
height: 300px;
width: 200px;
}
#rightCol {
padding-left:200px;
background-color: green;
height: 300px;
width: auto;
}
This is what I think you're after - forgive me if I'm wrong!
EDIT: Added outer container wrapper for right margin:
Updated HTML:
<div id="page">
<div id="outercontainer">
<div id="container">
<div id="leftCol">
LEFT
</div>
<div id="rightCol">
RIGHT
</div>
</div>
</div>
</div>
And the CSS:
#page{
background-color: purple;
height: 300px;
}
#outercontainer {
margin: 0 5% 0 0;
}
#container {
background-color: blue;
height: 300px;
margin: 0 auto;
min-width: 300px;
max-width: 600px;
position: relative;
}
#leftCol {
background-color: red;
height: 300px;
margin-right: 200px;
}
#rightCol {
position: absolute;
background-color: green;
width: 200px;
top: 0;
right: 0;
bottom: 0;
}
This gives the #container a min and max width, and the margins will show beyond the max. These are set quite small to show up well in JSFiddle.
leftCol will expand to fit the available space, and it's right-margin prevents it overflowing the rightCol.
rightCol is absolutely positioned (within #container) in the leftCol's margin.
JSFiddle here: https://jsfiddle.net/xuew6og5/1/
The #outerwrapper allows a visible right margin, until the page gets to minimum width at least. If you want the margins to be balanced, change its margin to 0 5%
Update: New JS Fiddle with right margin: https://jsfiddle.net/xuew6og5/2/
Update 3: Sorry, I missed your requirement for a max-width of 360px on the leftCol. Updated the CSS above, and a fiddle here: https://jsfiddle.net/xuew6og5/4/
In order to achieve the wanted effect you need to move the leftCol outside of your container and give your rightCol a margin-left with the size of your leftCol.
Also add a min-width and max-width to your lefCol and a width using calc to adjust it's width to your goals.
Note: lefCol width is calculated like this:
100% / 2 - (Container width / 2 - leftCol min-width)
So your altered html looks like this:
<div id="page">
<div id="leftCol">
LEFT
</div>
<div id="container">
<div id="rightCol">
RIGHT
</div>
</div>
</div>
Your new CSS looks like this:
#page{
background-color: purple;
}
#container {
background-color: blue;
width: 300px;
height: 300px;
margin: 0 auto;
}
#leftCol {
float: left;
background-color: red;
height: 300px;
min-width:100px;
width:calc(100%/2 - 50px);
max-width:200px;
}
#rightCol {
margin-left:100px;
background-color: green;
height: 300px;
width: 200px;
}
Take a look at the updated example:
https://jsfiddle.net/xxyv7nwf/2/
CSS solution using CSS3 calc.
Edited. According to OP updates.
#media screen and (min-width: 1600px) {
#container{
margin:0 auto;
}
}
body {
overflow-x:hidden;
}
#page{
background-color: purple;
height:300px;
}
#container{
background-color: blue;
min-width:980px;
max-width: 1140px;
}
#leftCol {
float: left;
background-color: red;
height: 300px;
width: calc(100% - 780px);
}
#rightCol {
float: left;
background-color: green;
height: 300px;
width: 780px;
}
HTML
<div id="page">
<div id="container">
<div id="leftCol">
LEFT
</div>
<div id="rightCol">
RIGHT
</div>
</div>
</div>

Proportionately increasing columns width

let's say I have number of columns of different width e.g.:
| 100 | 200 | 55 | 450 | empty space
And now I need to adjust the width of every column the way that the entire row fits in its container, and takes 100%.
I could of course set .row { max-width: 100% } and set the widest column to 100%, but I want to make it the way so every column takes available space proportionally. Any ideas?
You can use both display: table and display: table-cell.
As an example:
* {
box-sizing: border-box;
}
html, body {
width: 100%;
}
div {
width: 100%;
min-width: 100;
display: table;
}
div > div {
min-width: auto;
width: auto;
display: table-cell;
border-right: 1px solid #000;
text-align: center;
}
div > div:first-of-type {
border-left: 1px solid #000;
}
<div>
<div>ABCDE</div>
<div>FG</div>
<div>HIJKLM</div>
<div>N</div>
<div>OPQ</div>
<div>RSTUVWX</div>
<div>YZ</div>
</div>
Demo
You can also use percentages in your widths defining. (If you know the proportion of every element.)
div {
float: left;
}
#container {
width: 100%;
}
#e1 {
width: 30%;
}
#e2 {
width: 50%;
}
#e3 {
width: 20%;
}
<div id="container">
<div id="e1">XX</div>
<div id="e2">XX</div>
<div id="e3">XX</div>
</div>
Make sure your box-sizing is set correctly in CSS (box-sizing: border-box;), otherwise paddings and borders will overflow the width. :)

Emulating a fixed sidebar template issues

am trying to emulate this theme:
http://themetrust.com/demos/ink/?project=the-city-of-samba
But instead make the blog post always remain centered in the right hand side (space outside of the fixed sidebar) and have the blog post be of a % width.
I currently have this set up on my site, but am using a percentage based sidebar which looks awful.
Here is a JSfiddle recreating in basic terms the theme from above:
http://jsfiddle.net/Uyv6w/4/
All i am after is to make that grey inner div always remain centered inside the red content div.
Incase JSFiddle goes down and for future ref:
HTML:
<div id="container">
<div id="sidebar"></div>
<div id="content">
<div id="inner"></div>
</div
</div>
CSS:
* {
margin: 0; padding: 0;
}
html, body {
width: 100%;
height: 100%;
background-color: #333;
}
#container {
height: 100%;
width: 100%;
}
#sidebar {
height: 100%;
width: 100px;
background-color: #9b59b6;
position: fixed;
}
#content {
width: 100%;
background-color: #f00;
}
#inner {
width: 60%;
margin-left: 150px;
background-color: #888;
height: 1000px;
}
Thanks.
There are just 2 properties to change in ordre to make this work the way you want :
#content {
/* width: 100%; */
margin-left: 100px; /* the width of you sidebar.
Since #content is a div, a block-level element
, its width will be automatically 100%
, minus the margins */
background-color: #f00;
}
#inner {
width: 60%;
/* margin-left: 150px; */
margin-left: auto;
margin-right: auto; /* having margin-left & right set to auto will center your div.
you could also use "margin: 0 auto" */
background-color: #888;
height: 1000px;
}
I have updated you JSFiddle example here : http://jsfiddle.net/Uyv6w/5/
http://jsbin.com/requv/1/edit
if you set body, html (and the container) to height 100%, it will not be able to to scroll.
the height should be more then 100%.

Categories

Resources