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.
I have seen many things hinting at this possibility:
https://css-tricks.com/svg-text-typographic-designs/
SVG Scaling Text to fit container
http://www.petecorey.com/blog/2014/10/08/quest-for-scalable-svg-text/
https://discourse.wicg.io/t/auto-sizing-text-to-fit-container/1053/8
That first link is best, which shows how the text scales.
I have implemented a janky JavaScript version of this functionality, but I want to apply it to a lot of elements and I think SVG would be a better choice.
However, my attempt at copying the code from that first link doesn't end up with the same result, it doesn't work:
<head>
<style>
* {
padding: 0px;
margin: 0px;
}
/*div*/.ad-wrapper {
height: 0;
padding-top: 100%;
position: relative;
}
/*svg*/.ad {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: red;
color: black;
}
</style>
</head>
<body>
<div class="ad-wrapper">
<svg class="ad" xmlns="http://www.w3.org/2000/svg">
<text font-family="'proxima-nova', sans-serif">Mountain</text>
</svg>
</div>
</body>
Wondering what I'm doing wrong and how to fix it. I would like to have text centered in a responsive box (square even), where the padding on all sides of the text is proportionally the same as it scales up, without the need to use JavaScript at all.
Use always a viewBox attribute. A viewBox="0 0 100 100" will give you a square box. Give the text a x and a y. In this case you may use x="50" y="50" In order to center the text you may use text-anchor:middle;dominant-baseline:middle
* {
padding: 0px;
margin: 0px;
}
/*div*/.ad-wrapper {
height: 0;
padding-top: 100%;
position: relative;
}
/*svg*/.ad {
position: absolute;
width: 100%;
top: 0;
left: 0;
background: red;
color: black;
}
text{fill:black;text-anchor:middle;dominant-baseline:middle}
<div class="ad-wrapper">
<svg class="ad" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<text x="50" y="50" font-family="'proxima-nova', sans-serif">Mountain</text>
</svg>
</div>
I've tried changing between <line> and <path> in case the percentage parameters made a difference. But I'm still getting the same issue where the <svg> won't line up with my <img>'s. My end goal is to basically have the 2 ends of the <svg> lock into the border of the <img>'s. Any advice would be amazing.
Pen
html:
<div class="svg-benefitsContainer">
<svg class="benefitSVG" height="500%" width="100%" preserveAspectRatio="none">
<line class="benefitSVG1" x1="15%" y1="15%" x2="20%" y2="32%" />
</svg>
</div>
<div>
<img src="https://static1.squarespace.com/static/59a7820e2994ca11766093d3/t/5a09f06d9140b7f3b7d84274/1510600813361/quality.png" class="benefitsImgMed" />
<img src="https://static1.squarespace.com/static/59a7820e2994ca11766093d3/t/5a09f014ec212d1131cf09fc/1510600724150/flash.png" class="benefitsImgLig" />
css:
body {
background-color: black;
}
.benefitsImgMed,
.benefitsImgLig,
.benefitsImgArr,
.benefitsImgNig {
position: absolute;
padding: 10px;
border-color: white;
border-width: 5px;
border-radius: 50%;
border-style: solid;
}
.benefitsImgMed {
margin-left: 8%;
margin-top: 6%;
width: 13%;
}
.benefitsImgLig {
margin-top: 32%;
margin-left: 19%;
width: 13%;
}
.benefitsImgArr {
margin-left: 37%;
margin-top: 3%;
width: 13%;
}
.benefitsImgNig {
margin-left: 66%;
margin-top: 18%;
width: 13%;
}
.svg-benefitsContainer {
width: 100%;
height: 500%;
}
.benefitSVG {
position: absolute
}
.benefitSVG1 {
fill: none;
stroke: white;
stroke-width: 5;
/*L 125 315 q -20 200 115 190*/
}
Because SVG percentages work differently to HTML percentages.
The <svg> width and height are relative to its parent container width and height respectively.
The <line> x and width are relative to the SVG viewport width.
The <line> y and height are relative to the SVG viewport height.
The <image> left and top are relative to the browser width.
If you want it to be reliable, the safest solution is to put all of the objects in an SVG file together. It's a lot simpler to understand also.
body{background-color:black;}
line, circle {
fill: black;
stroke: white;
stroke-width: 0.5;
}
<div class="svg-benefitsContainer">
<svg class="benefitSVG" height="100%" width="100%" viewBox="0 0 100 100">
<line class="benefitSVG1" x1="14.5" y1="12.5" x2="25.5" y2="38.5" />
<circle cx="14.5" cy="12.5" r="8"/>
<image xlink:href="https://static1.squarespace.com/static/59a7820e2994ca11766093d3/t/5a09f06d9140b7f3b7d84274/1510600813361/quality.png"
x="8" y="6" width="13" height="13"
class="benefitsImgMed"/>
<circle cx="25.5" cy="38.5" r="8"/>
<image xlink:href="https://static1.squarespace.com/static/59a7820e2994ca11766093d3/t/5a09f014ec212d1131cf09fc/1510600724150/flash.png"
x="19" y="32" width="13" height="13"
class="benefitsImgLig"/>
</svg>
While giving a div equal height and width and setting a border radius of 100% makes a div "look" like a circle, the reality is that it is still a square in disguise. How can I make a div a "true" circle? For my purpose, I want to make items droppable only within the circle I create. By making a div look like a circle, items are still droppable outside of the circle at the edges.
$(".circle").droppable();
$(".drop").draggable({
containment: "parent"
});
.circle
{
width: 200px;
height: 200px;
border: 1px solid black;
border-radius: 100%;
display: inline-block;
}
.drop
{
border: 1px solid black;
display: inline-block;
}
.drop:hover
{
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<div class="circle">
<div class="drop">
Drop Me<br>
Outside
</div>
</div>
overflow: hidden;
box-sizing: border-box;
padding: 50px;
for container would do the thing :)
or if you can do it with flexbox then
overflow: hidden;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
use svg object like this, as suggested in comment
<svg class="circle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle fill="#FFF" cx="50" cy="50" r="50"/></svg>
I can propose to handle dragging manually and prevent unexpected behaviour if an element goes out of a circle. Add some additional javascript.
The following code can deal with just one corner (left-top). You can add three more conditions to handle all corners. It would be better to move a small circle rather than a rectangle - a circle has just one condition, rectangle has four ones.
// radius of a circle
var radius = 100;
$(".circle").droppable();
$(".drop").draggable({
containment: "parent",
drag: function( event, ui ) {
// position of a left top corner of a rectangle with respect
// to a center of a circle
var x = ui.position.left - radius,
y = radius - ui.position.top,
r = Math.sqrt(x*x + y*y);
// if distance from a center of a circle is greater than radius
// move it back into the circle
if (Math.floor(r) > radius) {
ui.position.top = radius - Math.round(radius * y / r);
ui.position.left = Math.round(radius * x / r) + radius;
}
}
});
.circle
{
width: 200px;
height: 200px;
border: 1px solid black;
border-radius: 50%;
display: inline-block;
}
.drop
{
border: 1px solid black;
display: inline-block;
}
.drop:hover
{
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<div class="circle">
<div class="drop">
Drop Me<br>
Outside
</div>
</div>
UPD. Example of dragging circle was considered in another question.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I was wondering if there is a way to fill a specific icon or sprite to a designated percentage - i.e. 20% or something like that. I am trying to create a responsive shape or image that will serve as fluid chart, of sorts. I know the below is not a great example - the svg is also in font form. I want to dynamically fill this image to a specified % in my code.
So let's say a data point reads 20%, I want the heart to fill with another color (e.g. color:#DA1C5C) up to 20%, leaving the rest the original color. The code I'm working with is using a straight icon font and not the image svg, but it's not hosted yet.
<div class="icon">
<i class="icon-doubleheart">
<img src="https://s3.amazonaws.com/yourcareassets/doubleheart.svg">
</i>
With SVG: fiddle
HTML:
<div class="icon">
<div id='blackIcon' class="icon-doubleheart">
<img src="https://s3.amazonaws.com/yourcareassets/doubleheart.svg"/>
</div>
<div id='holdci'>
<div id='colorIcon' class="icon-doubleheart">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
<g>
<path class='newColor' d="M353.1,137c-37.2-17.2-85.9-1-103.1,36.1c-17.2-37.1-65.9-53.3-103.1-36.1c-27.5,12.7-45,39.2-42.7,72.8h0.2 c1.4,14.1,6.1,29.4,15.2,45.5c22.2,39.4,61.6,69.1,130.3,122.3c68.7-53.2,108.1-82.9,130.3-122.3c9.1-16,13.8-31.3,15.2-45.5h0.2 C398,176.2,380.5,149.7,353.1,137z"/>
<path class='newColor' d="M493.5,124c-11.1-34.6-36.2-62.5-70.5-78.6c-18.8-8.8-40-13.4-61.4-13.4c-45.8,0-87.4,20.7-111.6,54.2 c-24.2-33.5-65.8-54.3-111.6-54.3c-21.3,0-42.6,4.6-61.4,13.4c-34.4,16-59.4,44-70.6,78.6C0,144.3-3.9,173.4,6,209.7h0.7 c4.3,14.9,10.8,31,20.4,48.2c36.1,64.4,99.1,113.5,203.5,194.8l19.4,15.1l19.5-15.2C373.9,371.4,436.9,322.3,472.9,258 c9.7-17.2,16.2-33.3,20.4-48.2h0.7C503.9,173.4,500,144.3,493.5,124z M468.8,207.2h-0.7c-4,12.6-9.6,25.5-16.9,38.6 c-33.6,60-95.1,107.9-197,187.3l-4.2,3.3l-4.1-3.2C144,353.7,82.4,305.8,48.8,245.8c-7.3-13-13-25.9-16.9-38.5h-0.7 c-8-26.8-8.4-52.4-1-75.5c9-28,29.4-50.6,57.4-63.7c15.6-7.3,33.2-11.1,50.9-11.1c44.3,0,83.7,23.2,100.3,59.1l11.3,24.5l11.3-24.5 C277.9,80.2,317.2,57,361.6,57c17.7,0,35.3,3.8,50.9,11.1c28,13.1,48.4,35.7,57.3,63.6C477.2,154.8,476.8,180.4,468.8,207.2z"/>
</g>
</svg>
</div>
</div>
</div>
CSS:
.icon {
width: 10em;
height: 10em;
}
#blackIcon {
width: 100%;
height: 100%;
}
#holdci {
margin-top: -100%;
overflow: hidden;
width: 0;
height: 99%;
}
#colorIcon {
width: 10em;
height: 10em;
}
.newColor {
fill: #DA1C5C;
}
JS:
var fill = 0;
var update = setInterval(function() {
fill += 1;
if (fill <= 100) {
$('#holdci').css('width', (fill+'%'));
} else {
clearInterval(update);
}
}, 100);
With pure CSS:
HTML:
<div id='Icon'>
<div id='IconText'>f</div>
<div id='fillIcon'></div>
</div>
CSS:
#Icon {
position: absolute;
width: 2em;
height: 2em;
border: 0.125em solid blue;
border-radius: 0.2em;
}
#fillIcon {
position: absolute;
z-index: 0;
width: 100%;
height: 0;
margin-top: 100%;
background-color: blue;
}
#IconText {
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
line-height: 150%;
text-align: center;
color: #cccccc;
font-weight: bold;
font-family: consolas;
font-size: 1.5em;
}
JS:
var fill = 0;
var update = setInterval(function() {
fill += 1;
$('#fillIcon').css('height', (fill+'%'));
$('#fillIcon').css('margin-top', ((100 - fill)+'%'));
if (fill === 100) {
clearInterval(update);
}
}, 100);
With an image: fiddle
HTML:
<div id='Icon'>
<div id='IconText'><img style='width: 100%; height: 100%;' src='http://bellybusting.com.au/wp-content/uploads/2014/03/fb.jpg'/></div>
<div id='fillIcon'><img style='width: 2em; height: 2em;' src='http://getdesign.org/wp-content/uploads/2013/08/Facebook-icon-with-green-background-56.png'/></div>
</div>
CSS:
#Icon {
position: absolute;
width: 2em;
height: 2em;
}
#fillIcon {
position: absolute;
z-index: 2;
width: 100%;
height: 0%;
margin-top: 0;
overflow: hidden;
}
#IconText {
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
line-height: 150%;
text-align: center;
color: #cccccc;
font-weight: bold;
font-family: consolas;
font-size: 1.5em;
}
JS:
var fill = 0;
var update = setInterval(function() {
fill += 1;
$('#fillIcon').css('height', (fill+'%'));
//$('#fillIcon').css('margin-top', ((100 - fill)+'%'));
if (fill === 100) {
clearInterval(update);
}
}, 100);
You can, here's 2 methods for your example of 20% width:
Method 1: HTML image
HTML:
<div>
<img src="myImage.jpg" width="135" height="155" class="responsiveImage">
</div>
And the CSS:
div {
max-width:100%;
width:20%;
}
img.responsiveImage {
width:100%;
max-width:100%;
height:auto /* only necessary to override the 'Height' attribute if imcluded */
margin:0 auto;
}
The results will be a scaleable hardcoded image. You can check out the Fiddle here.
If you want to use CSS for more control, you can use this instead:
Method 2: CSS background image
HTML:
And CSS, based on this helpful answer:
div.responsiveImage {
width:20%;
padding:12% 0; /* The 20:24 ratio of width to combined padding matches the dimensions of the image */
background: url(myImage.jpg) no-repeat top left;
background-position:50% 50%; /* Sets reference point to scale from */
background-size:cover;
border:solid 1px red;
}
Here's the fiddle of it in action.
The width and top and bottom padding is calculated by the ratio of width:height of the image you want to use. In the Fiddle examples, I've used one that is 135px wide by 155px high. To obtain the ratio, I used this:
(155/135)*100 = 114.814
This means the height is 114% the value of the width. Hence, if the width = 20%, the height is (20 * 114814)/100, or 23%. In my case, I split this into 2 by applying this equally as top and bottom padding (As monitors can't display half a pixel, I rounded it up).
Bear in mind that the padding value for the height of the image will change once it has a wrapper around it. Also, the overall height of the container will change if any content is added.