This question already has an answer here:
How to create a curved line with gradient?
(1 answer)
Closed 3 years ago.
I am using css, div only. I am trying to draw these type of lines :
.line {
width: 1px;
height: 100px;
background-color: black;
position: absolute;
border-radius: 50%/100px 100px 0 0;
}
#line1 {
top: 100px;
left: 50px;
}
#line2 {
top: 220px;
left: 150px;
height: 115px;
transform: rotate(120deg);
-webkit-transform: rotate(120deg);
-ms-transform: rotate(120deg);
}
<div class="line" id="line1"></div>
<div class="line" id="line2"></div>
I am trying to use border-radius: 50%/100px 100px 0 0; but no idea what is going wrong as nothing happens. Sorry for bad English,this is what i am trying to do. Please help.
You could use SVGs to achieve what you want.
See code below
Read more here -> SVG
<svg width="190" height="160" xmlns="http://www.w3.org/2000/svg">
<path d="M 5 50 C 40 10, 65 10, 75 40 S 100 100, 180 20" stroke="black" fill="transparent"/>
</svg>
EDIT: if you can't use SVG or other solutions besides div elements. and css you could use this.
If you can use ONLY 1 DIV element. Then use the below css on pseudo-elements before and after instead of line1 and line2
.line1 {
border-radius:100px 0 0 0 ;
border-width: 2px 0 0 2px;
margin-left:100px;
}
.line2 {
border-radius:0 0 100px 0 ;
border-width: 0 2px 2px 0 ;
}
.line {
border-color:red;
border-style: solid;
height:100px;
width: 100px;
}
<div class="line line1"></div>
<div class="line line2"></div>
Related
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>
This is how to diagonally "divide" a square into 4 parts:
div {
width: 0;
height: 0;
border-top: 50px solid red;
border-right: 50px solid blue;
border-bottom: 50px solid green;
border-left: 50px solid yellow;
}
<div>
</div>
(result)
I want to attach an event to each colored area - but of course you can't attach an event to a border. How should I do?
Here is one way to do it. Nested DIVs. I used wrapper with a a grid to lay them in the 2x2 pattern, then translated and rotated the wrapper. Clipped using the outermost div. Each one is easy to use the onclick for, and you don't need to do extra logic. Just a lot more effort to setup.
I've also got this set up so that you can easily change the size of the squares. However, this definitely won't work in IE, but I don't think we really need to worry about that.
Working codepen
document.querySelector(".red").onclick = () => alert("red");
document.querySelector(".blue").onclick = () => alert("blue");
document.querySelector(".yellow").onclick = () => alert("yellow");
document.querySelector(".green").onclick = () => alert("green");
.clip {
--size: 200px;
height: var(--size);
width: var(--size);
overflow-x: hidden;
overflow-y: hidden;
}
.rotate {
height: calc(var(--size) * 1.5);
width: calc(var(--size) * 1.5);
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
transform: translate(-50%, -50%) translate(calc(var(--size) * 0.5), calc(var(--size) * 0.5)) rotate(45deg) ;
}
.red {
background: red;
}
.blue {
background: blue;
}
.yellow {
background: yellow;
}
.green {
background: green;
}
<div class="clip">
<div class="rotate">
<div class="red"> </div>
<div class="blue"> </div>
<div class="yellow"> </div>
<div class="green"> </div>
</div>
</div>
If you want to pursue a single div/different logic depending on location, this might help.
I just wrote this in the console of this page:
document.body.addEventListener("click",(e)=>console.log(e))
And clicked, in this order, on these portions: "yellow", "red", "blue", "green" of your image. ( I held ctrl while clicking, so that it would open the image in new tab and this page would persist)
The resulting events (4 loggeed, ofc) had a path attribute that said on which element I clicked (in this case, principal one was img), and the offsetX & offsetY relative to this element
The relation was:
{
"yellow": {offsetX: 18, offsetY: 59},
"red": {offsetX: 59, offsetY: 25},
"blue": {offsetX: 85, offsetY 46},
"green": {offsetX: 61, offsetY: 78},
}
So yeah, you could use, from the MouseEvent:
offsetX
The offsetX read-only property of the MouseEvent interface provides the offset in the X coordinate of the mouse pointer between that event and the padding edge of the target node.
offsetY
The offsetY read-only property of the MouseEvent interface provides the offset in the Y coordinate of the mouse pointer between that event and the padding edge of the target node.
And determine where user clicked.
You can use clip path to make triangles and use some positioning to get them in the correct spots.
document.querySelector('.sq-tri').addEventListener("click", (evt) => {
console.log(evt.target.getAttribute('data-location'))
})
.sq-tri {
display: relative;
width: 5em;
height: 5em;
}
.tri {
position: absolute;
}
.tri-up,
.tri-down {
width: 5em;
height: 2.5em;
}
.tri-left,
.tri-right {
width: 2.5em;
height: 5em;
}
.tri:hover {
background-color: lime;
cursor: pointer;
}
.tri-up {
margin-top: 2.5em;
background-color: yellow;
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
}
.tri-down {
background-color: red;
clip-path: polygon(50% 100%, 0% 0%, 100% 0%);
}
.tri-left {
background-color: green;
margin-left: 2.5em;
clip-path: polygon(100% 100%, 100% 0, 0 50%);
}
.tri-right {
background-color: blue;
clip-path: polygon(0 100%, 0 0, 100% 50%);
}
<div class="sq-tri">
<div class="tri tri-down" data-location="top"></div>
<div class="tri tri-right" data-location="left"></div>
<div class="tri tri-left" data-location="right"></div>
<div class="tri tri-up" data-location="bottom"></div>
</div>
Use an SVG as detailed in this answer
Note: As each of the elements inside the SVG has an ID, you should be able to target them with JS/Jquery.
svg {
display: block;
width: 200px;
height: 200px;
margin: 25px auto;
border: 1px solid grey;
stroke: #006600;
}
#buttons polygon:hover {
fill: orange;
}
#top {
fill: #cc3333;
}
#right {
fill: #663399;
}
#left {
fill: #bada55;
}
<svg viewbox="0 0 100 100">
<g id="buttons">
<polygon id="top" points="0,0 100,0 50,50" />
<polygon id="right" points="100,0 50,50 75,75 100,100" />
<polygon id="bottom" points="0,100 50,50 75,75 100,100" />
<polygon id="left" points="0,0 25,25 50,50 0,100" />
</g>
</svg>
I'm trying to add click events to an SVG Element which has visible overflow and a shape element(circle/path) inside it which overflows the SVG.
On Safari(9,10,11), click event doesn't work in the area where the shape element(circle/path) overflows while it works fine in the area present within the SVG.
var count = 0;
function clickMe() {
console.log("in click func");
count++;
document.getElementById("counter").innerHTML = count;
}
#counter {
font-size: 2em;
}
#starSvg {
pointer-events: auto;
overflow: visible;
position: absolute;
left: 200px;
top: 250px;
border: 1px solid red;
}
#starPolygon {
overflow: visible;
fill: rgba(0, 153, 219, 1);
pointer-events: visiblePainted;
stroke-width: 4;
stroke-linecap: square;
stroke-linejoin: round;
stroke: rgba(219, 0, 153, 1);
cursor: pointer;
shape-rendering: geometricPrecision
}
p {
margin: 10px 0;
}
<div>
<p>Open this webpage on Chrome & safari</p>
<p>On Chrome: Click work on all four hands of the star.</p>
<p>On Safari: Click works only on the hands inside the red area(SVG bounding Rect).</p>
<p style="position: absolute; top: 100px; left: 200px;">Click Event Counter:
<span id="counter">0</span>
</p>
<div class="containter">
<svg onclick="clickMe()" id="starSvg" width="100%" height="100%">
<g width="100%" height="100%" transform="" style="overflow: visible; transform: rotate(45deg) translate(0, 0);">
<polygon id="starPolygon" shape-rendering="geometricPrecision" points="0 -90,15 -15,90 0,15 15,0 90,-15 15,-90 0,-15 -15"></polygon>
</g>
</svg>
</div>
</div>
Is this also a bug in Safari? The click event works fine in all browsers including IE.
This mirrors Webkit bug report #140723 here: https://bugs.webkit.org/show_bug.cgi?id=140723
That bug report links to this codepen example reproducing the exact same results you've found:
https://codepen.io/anon/pen/pvPQqY
And with the fix as I've described below applied here:
https://codepen.io/anon/pen/YeOmGW
===========
Edited for clarity: The evidence is clear that the initial clipping is taking effect at the outer most view port (svg) boundary, while at the same time the overflow property is allowing the visibility of the shape outside that clipped area. In effect rendering the pointer events void.
Said differently, evidence that clipping is applied IAW the first sentence here: http://w3.org/TR/SVG11/masking.html#AutoClipAtViewportNotViewBox , while at the same time conforming to the overflow rules (last three) here: http://w3.org/TR/SVG11/masking.html#OverflowAndClipProperties is the cause of this issue with Safari;
To overcome this issue, the OP must create a wrapper viewport to create a (workaround) solution to the dilemma created by the inconsistent implementations.
This is similar to adding any other HTML structure that might be required to wrap required content. (I'm really focused on helping solve the problem)
Hope this helps.
var count = 0;
document.querySelector('svg').addEventListener('click',clickMe);
function clickMe(e) {
console.log("clicked on: " + e.target.id);
count++;
document.getElementById("counter").innerHTML = count;
}
#counter {
font-size: 2em;
}
#starSvg {
pointer-events: auto;
position: absolute;
width: 100%;
height: 100%;
left:0;
top:0;
}
#starPolygon {
transform: translate(50%, 50%) rotate(45deg);
fill: rgba(0, 153, 219, 1);
stroke-width: 4;
stroke-linecap: square;
stroke-linejoin: round;
stroke: rgba(219, 0, 153, 1);
cursor: pointer;
shape-rendering: geometricPrecision
}
#starClip {
width: 100%;
height: 100%;
stroke-width: 1;
stroke: red;
fill: transparent;
}
p {
margin: 10px 0;
}
<div>
<p>Open this webpage on Chrome & safari</p>
<p>On Chrome: Click work on all four hands of the star.</p>
<p>On Safari: Click works only on the hands inside the red area(SVG bounding Rect).</p>
<p style="position: absolute; top: 100px; left: 200px;">Click Event Counter:
<span id="counter">0</span>
</p>
<div class="containter">
<svg id="starSvg">
<rect id="starClip" x="50%" y="50%"></rect>
<g>
<polygon id="starPolygon" x="0" y="0" points="0 -90,15 -15,90 0,15 15,0 90,-15 15,-90 0,-15 -15"></polygon>
</g>
</svg>
</div>
</div>
Seems to be fixed in version 11.1 of Safari.
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>
I'm trying to achieve something like the following:
The diagonal split should go from the top right corner to the bottom left corner, at an exact angle so that both sides are totally equally proportioned.
I found an example online, but it was for wide aspect images, while trying to modify it to fit my 1:1 ratio purpose, I can't seem to get the bottom image to line up properly, but the top one works fine.
The diagonal split is also off-center, and the yellow background is there to show the area that should be filled by the lower image. The lower image should be the same size as the top one, just with the bottom half instead of the top half showing.
I have created a fiddle to demonstrate: https://jsfiddle.net/uxuv17at/2/
HTML
<div class="split-image-container">
<div class="split-image-bottom">
<img src="https://merkd.com/usr/members/icons/thumb.php?src=1435366066.9.png&w=300" alt="Just Another Clan" title="Just Another Clan" />
</div>
<img src="https://merkd.com/usr/teams/icons/thumb.php?src=1441676463.1.jpg&w=300" alt="ExtraordinaryKillers" title="ExtraordinaryKillers" />
</div>
CSS
.split-image-container{
height: 300px;
width: 300px;
overflow: hidden;
position: relative;
border: 1px solid black;
padding: 0;
background-color: green;
}
/*Rotate this div and position it to cut the rectangle in half*/
.split-image-bottom{
transform: rotate(315deg);
position: absolute;
top: 85px;
left: 70px;
overflow: hidden;
height: 350px;
width: 350px;
background: yellow;
}
/*Apply exact opposite amount of rotation to the .image2 class so image appears straight */
/*Also align it with the top of the rectangle*/
.split-image-bottom img{
transform: rotate(45deg);
position: absolute;
top: -50px;
left: 15px;
}
CSS Only
Pure CSS solution using the clip-path property. Browser support is pretty bad though.
.split-image-container{
height: 300px;
width: 300px;
position: relative;
}
img{
width:100%;
height:100%;
position:absolute;
}
.clip{
-webkit-clip-path: polygon(100% 0%, 0% 100%, 100% 100%);
clip-path: polygon(100% 0%, 0% 100%, 100% 100%);
}
<div class="split-image-container">
<img src="https://merkd.com/usr/members/icons/thumb.php?src=1435366066.9.png&w=300" alt="Just Another Clan" title="Just Another Clan"/>
<img src="https://merkd.com/usr/teams/icons/thumb.php?src=1441676463.1.jpg&w=300" alt="ExtraordinaryKillers" title="ExtraordinaryKillers" class="clip"/>
</div>
SVG
This one uses the svg clippath. Browser support should be a lot better.
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<clipPath id="clipPolygon">
<polygon points="100 0,0 100,100 100">
</polygon>
</clipPath>
<image viewBox='0 0 100 100' preserveAspectRatio='none' height="100" width="100" xlink:href="https://merkd.com/usr/members/icons/thumb.php?src=1435366066.9.png&w=300" />
<image viewBox='0 0 100 100' preserveAspectRatio='none' height="100" width="100" clip-path="url(#clipPolygon)" xlink:href="https://merkd.com/usr/teams/icons/thumb.php?src=1441676463.1.jpg&w=300" />
</svg>