CSS split a square into 4 triangles - html

I am currently trying to make a square be 4 triangles of equal size that have hover events on them.
I am creating the triangles like this,
.right, left, .top, .bottom {
position: relative;
width: 26px;
}
.right:before{
position: absolute;
display: inline-block;
border-top: 26px solid transparent;
border-right: 26px solid #eee;
border-bottom: 26px solid transparent;
left: 26px;
top: 0px;
content: '';
}
What I am finding is that each triangle sits above one another meaning only one triangle can be hovered, here is my example,
http://codepen.io/anon/pen/qdmbKz
As you can see only the bottom triangle (hover at the bottom of the square) is hoverable. What am I doing wrong? Is there a better way of doing this?

As you have already indicated in your question, the reason why the hover works only on the bottom triangle and not the others is because the container of the bottom triangle is placed on top of the container of the other three triangles.
While using the border trick to produce triangles, the actual shape is still a square. It gets the triangle appearance only because the other three borders are transparent. Now when you hover on the shape you are actually hovering the transparent areas of the bottom triangle and not the containers of the other triangles which is why their respective hover events don't get triggered.
I would personally recommend using SVG for these type of things but the shape is not all that complex to achieve with CSS either.
SVG:
In SVG, you could make use of the polygon elements to create four triangles within the square and each polygon is hover-able separately. If they should have their own target links, you can also enclose the polygons within an a (anchor) tag.
In the snippet, I have implemented the anchor only for one triangle
.square {
height: 400px;
width: 400px;
overflow: hidden;
}
svg {
height: 100%;
width: 100%;
}
polygon {
fill: aliceblue;
stroke: crimson;
stroke-linejoin: round;
}
polygon:hover {
fill: cornflowerblue;
}
<div class='square'>
<svg viewBox='0 0 100 100'>
<a xlink:href='http://google.com'>
<polygon points='5,5 50,50 95,5' />
</a>
<polygon points='5,5 50,50 5,95' />
<polygon points='5,95 50,50 95,95' />
<polygon points='95,5 50,50 95,95' />
</svg>
</div>
CSS:
This is an adaptation of the answer posted by here by web-tiki. I am posting a separate answer because the shape in this question is much simpler and doesn't require as much work as the other one.
The square is split into four equal sized hover-able triangles using the following method:
The container is a square and has borders on all its sides. The borders are required on the parent because diagonal lines on the triangle are much much more difficult to achieve with CSS.
Four child elements are added to the container whose height and width are calculated using Pythagoras theorem. They are then positioned such that their top left corner is on the center point of the square (to help with the rotation).
All the child elements are rotated by the appropriate angles to form the triangles. The transform-origin is set as top left to have the rotation done with the parent square's center point as the axis.
The parent has overflow: hidden to prevent the other half of each square from being visible.
Note that adding text into the 4 triangles will not be straight-forward because they would also be rotated. The text would have to be put inside a child element which must either be counter rotated.
Note: The script included in the demo is the prefix free library which is used to avoid browser prefixes.
.square {
position: relative;
height: 200px;
width: 200px;
border: 2px solid crimson;
overflow: hidden;
transition: all 1s;
}
.top,
.left,
.right,
.bottom {
position: absolute;
height: calc(100% / 1.414);
width: calc(100% / 1.414);
top: 50%;
left: 50%;
border: 1px solid crimson;
transform-origin: 0% 0%;
}
.right {
transform: rotate(-45deg);
}
.bottom {
transform: rotate(45deg);
}
.top {
transform: rotate(-135deg);
}
.left {
transform: rotate(135deg);
}
.square > div:hover {
background: tomato;
}
/*Just for demo*/
.square:hover{
height: 300px;
width: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='square'>
<div class="top"></div>
<div class="right"></div>
<div class="bottom"></div>
<div class="left"></div>
</div>

Related

How to draw a circle inside a triangle css

I am trying to put this circle in the center of the triangle. I set the class triangle to display flex but it didn't work. Please help me.
The code:
body {
display: flex;
align-items: center;
justify-content: center;
}
.triangle {
position: relative;
width: 0;
height: 0;
border-left: 300px solid transparent;
border-right: 300px solid transparent;
border-bottom: 300px solid black;
}
.circle {
position: absolute;
width: 200px;
height: 200px;
border-radius: 50%;
background: blue;
}
<div class="triangle">
<div class="circle">
</div>
</div>
One of the easiest – non SVG – ways to achieve this is as below, with explanatory comments in the code:
.collage {
/* using grid layout means we can easily
position the elements in the same place
without nesting them: */
display: grid;
/* effectively the same as:
justify-content: center;
align-contents: center;
to place the items in the center along
the block and inline axes: */
place-items: center;
}
.triangle {
/* allows us to set the aspect-ratio, which causes
the browser to compute one axis of the element
based on the value we specify for 'other' axis;
here we specify a height of 300px, so the browser
calculates the other axis to 600px, making the
triangle-shape twice as wide as its height: */
aspect-ratio: 2 / 1;
background-color: #000;
/* using clip-path, with the CSS polygon() function,
to specify a list of coordinates outside of which
the element is clipped, instead of using the
border hack to create a triangle: */
clip-path: polygon(50% 0, 100% 100%, 0 100%);
/* positions the element in the first grid-row
and first grid-column: */
grid-area: 1 / 1;
height: 300px;
z-index: 1;
}
.circle {
/* a shorthand for an aspect-ratio of: 1 / 1,
which causes the browser to calculate the
unknown axis to be same length as the
specified axis (again, the height): */
aspect-ratio: 1;
background-color: #00f;
border-radius: 50%;
grid-area: 1 / 1;
height: 210px;
/* to place the element higher in the visual
stack, 'closer' to the viewer: */
z-index: 10;
}
<div class="collage">
<div class="triangle"></div>
<div class="circle"></div>
</div>
JS Fiddle demo.
Of course, if you're prepared to use SVG:
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" xml:space="preserve">
<!-- this element is the background upon which
the triangle and circle appear: -->
<rect id="background"
<!-- we fill the shape with black, the 'fill'
being the 'background-color' -->
style="fill: #fff;"
<!-- these attributes determine the placement of
the element, the x and y coordinates
of the upper-left corner: -->
x="-300" y="-300"
<!-- determines the width and height: -->
width="600" height="600"
<!-- moves the element across the SVG, in the
x and y axes: -->
transform="translate(300 300)" />
<path id="triangle"
style="fill: #000;"
<!-- this is the path of the triangle, the enclosed
space being the filled portion: -->
d="M-37.43 32.41 0-32.41l37.43 64.82z"
transform="matrix(7.36 0 0 4.99 300 300)" />
<circle id="circle"
style="fill: #00f;"
<!-- we specify the radius of the <circle>: -->
r="35"
<!-- and move it within the SVG for positioning: -->
transform="matrix(3.01 0 0 3.01 300 300)" />
</svg>
JS Fiddle demo.
SVG is a little complex to explain, so unfortunately I've largely abdicated from that responsibility and left a link – in the bibliography below – from which you (and others) can learn more about it.
It's also worth stating that my own knowledge of SVG is limited, and I tend to use a program to create them, such as InkScape (other programs are, of course, available) or an online generator, as I did here.
References:
align-contents.
aspect-ratio.
background-color.
clip-path.
display.
grid-area.
height.
justify-content.
place-items.
<SVG>.
SVG element reference.
z-index.
Bibliography:
"A Complete Guide to Grid," CSS-Tricks.
"CSS Grid Layout," Mozilla Developer Network.
"SVG Tutorial," Mozilla Developer Network.
You can consider one element to draw both shapes:
.box {
width: 400px;
aspect-ratio: 2;
clip-path: polygon(50% 0, 100% 100%, 0 100%);
background: radial-gradient(17% 34% at 50% 60%, blue 98%,#000); /* 34 = 17*2 */
}
<div class="box"></div>
You must to set top, right, left, bottom for your circle class in css.
For example:
.circle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%) //optional
width: 200px;
height: 200px;
border-radius: 50%;
background: blue;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
.triangle {
position: relative;
width: 0;
height: 0;
border-left: 300px solid transparent;
border-right: 300px solid transparent;
border-bottom: 300px solid black;
}
.circle {
width: 200px;
height: 200px;
border-radius: 50%;
background: blue;
position: absolute;
top: 75px;
right : 50%;
transform: translateX(50%);
}
<div class="triangle">
<div class="circle">
</div>
</div>

CSS ring with background and percentage border width

I'm seeking for some advice on creating a "ring" shape in CSS. Here's some important detailed goals I need to achieve:
the ring border thickness must be a percentage number, not rm or absolute pixel number, so that the ring shape can be fully responsive based on container size;
The ring border need to have a background, for my scenario, the background could be sometimes a combination of 3-4 solid colors, or a gradient color;
The filling of the ring must be transparent so user can see the background through it.
Here's a quick example:
Here are a few attempts I used:
Make a border-radius: 50% div with only border width but soon I noticed the border width cannot be a percentage number;
SVG clipping a round div to a ring shape. so far I was not able to successfully make it working... If this is the right approach, please share some snippet.
You can achieve this considering mask where the idea is to use a radial-gradient to create the hole and use fixed value which will make the visible part (the thickness) to be responsive.
.box {
border-radius:50%;
background:linear-gradient(red,purple,orange);
-webkit-mask: radial-gradient(transparent 89px,#000 90px);
mask: radial-gradient(transparent 89px,#000 90px);
}
.box:before {
content:"";
display:block;
padding-top:100%;
}
.container {
margin:0 auto;
max-width:200px;
animation:change 3s linear alternate infinite;
}
#keyframes change{
to {
max-width:400px;
}
}
body {
background:linear-gradient(to right,yellow,pink);
}
<div class="container">
<div class="box">
</div>
</div>
Making responsive rings in CSS is tough. The best I've found is to simply create two circles stacked on top of each other where the top circle's background is the same as the container background. You could do this with 2x elements like in my example or with a pseudo-class.
Pros:
You get lots of control
Easily add other content (like pie charts) since the content is "masked"
Cons:
Background needs to be a flat color and nothing will show through the ring
.outer {
width: 200px;
height: 200px;
border-radius: 50%;
position: relative;
background-color: #9273B0;
margin: 10px;
cursor:pointer;
}
.inner {
position: absolute;
width: 50%;
height: 50%;
border-radius: 50%;
background-color: #ffffff;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transition: all 0.5s ease-out;
}
.outer:hover .inner {
width: 90%;
height: 90%;
}
<div class="outer">
<div class="inner"></div>
</div>
If you MUST see the background through the ring, I'd look into a SVG clip path but that gets really complicated pretty quick.
In order to maintain percentage values you can try using a radiel-gradient. However the borders tend to get a little choppy looking.
.circle {
display: flex;
justify-content: center;
align-items: center;
font-family: sans-serif;
color: #fff;
height: 100%;
width: 100%;
border-radius: 50%;
background: radial-gradient(ellipse at center,
rgba(255,113,12,0) 60%,
rgba(255,113,12,1) 51.5%);
}
Example: https://codepen.io/SROwl/pen/BMEJzj
You could use vw or vh as a metric. The border-width will be calculated based on the viewport width or height depending what you choose. You'll have to do some calculation of what value you want to use:
.ring {
border: 10vw solid red;
border-radius: 50%;
height: 100%;
position: absolute;
width: 100%;
}
https://codepen.io/anon/pen/ErJbxN?editors=1100
With JS: https://codepen.io/anon/pen/rPbYvm

CSS triangle to fit variable sized div elements

Please refer to my fiddle. I was aiming to create a triangle (to be placed inside a div), and make it fit exactly (corner to corner).
Here are the rules outlined:
Place the triangle inside all the div elements.
The bottom left corner of the triangle should fit the bottom left corner inside all the divs.
The top right corner of the triangle should fit the top right corner inside all the divs.
The divs has fixed width and height BUT in real life they are all unknown, inherited from a parent.
The angle of the diagonal will be different for every div but that is ok.
Use borders, gradients, transform or SVG to solve the problem. I would not like to use fixed pixel solutions like canvas or PNG.
.one {
width: 100px;
/* Unknown */
height: 30px;
/* Unknown */
background: #ccc;
}
.two {
width: 40px;
/* Unknown */
height: 90px;
/* Unknown */
background: #aaa;
}
.three {
width: 70px;
/* Unknown */
height: 70px;
/* Unknown */
background: #aaa;
}
.triangle {
width: 0;
height: 0;
border-style: solid;
border-width: 0 0 50px 50px;
border-color: transparent transparent #007bff transparent;
}
<div class="one"></div>
<br>
<div class="two"></div>
<br>
<div class="three"></div>
<br>
<div class="triangle"></div>
JSFiddle Reference
Achieving this effect with border will not be possible for dynamically sized containers because they cannot take percentage values or adapt based on a change in dimension of the container. They can only use either pixel or viewport units. Both those wouldn't be of much use for a dynamic container.
Transforms can be used by placing a pseudo-element on top of the containers but they would need calculations for height and width of the element based on trigonometric equations. The simpler ones would be the gradient and SVG approaches.
Using Gradient:
You can do this using a gradient with to [side] [side] syntax. This is responsive and would work for all container sizes. The only drawback is that there would be jagged lines in some cases where the width or height is too large compared to the other.
One advantage of this is that it doesn't require any extra elements (SVG or HTML, not even pseudos) but the drawback will be when hover and click effects are required for the triangle alone (restricted to the triangle's boundaries). Since the element is still a rectangle/square, the hover or click effect will be triggered even when the mouse is outside the triangle but within the container.
.one {
width: 100px;
height: 30px;
background-color: #ccc;
}
.two {
width: 40px;
height: 90px;
background-color: #aaa;
}
.three {
width: 70px;
height: 70px;
background-color: #aaa;
}
div {
background-image: linear-gradient(to top left, blue 50%, transparent 51%);
}
<div class="one"></div>
<br>
<div class="two"></div>
<br>
<div class="three"></div>
<br>
Using SVG:
You could also do it with SVG path element like in the below snippet. The SVG has to be positioned absolutely with respect to the container and have 100% of the parent's width and height.
The advantage of using SVG for the triangle over gradients is that hover and click effects can be added to the triangle alone.
.one {
width: 100px;
height: 30px;
background-color: #ccc;
}
.two {
width: 40px;
height: 90px;
background-color: #aaa;
}
.three {
width: 70px;
height: 70px;
background-color: #aaa;
}
div{
position: relative;
}
div > svg {
position: absolute;
height: 100%;
width: 100%;
}
svg path{
fill: #0007bf;
}
svg path:hover{
fill: crimson;
}
<div class="one">
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<path d='M100,0 L100,100 0,100z' />
</svg>
</div>
<br>
<div class="two">
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<path d='M100,0 L100,100 0,100z' />
</svg>
</div>
<br>
<div class="three">
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<path d='M100,0 L100,100 0,100z' />
</svg>
</div>
<br>
in gradient
style
.triangle {
width: 100%;
height: 100%;
background: linear-gradient(to bottom right, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 50%, #007bff 50%, #007bff 100%)
}
html
<div class="one">
<div class="triangle"></div>
</div><br>
<div class="two">
<div class="triangle"></div>
</div><br>
<div class="three">
<div class="triangle"></div>
</div>

css 3D transform elements disappear when perpendicular to viewer

html elements, being two dimensional,
have width & height but no thickness. not even a single pixel.
Therefore, when applying a 3D transform to an element, if its rotated perpendicularly to the viewer, it disappears.
Is there some property that can be set to remedy this situation?
It seems that the browsers should calculate elements as being 1 pixel thick if they are rotated in 3d.
I don't know if this solution applies to your case, due to the lack of details in your questions.
But, in a general way, you can do this adding a border to the element you are rotating.
There is an example: http://jsfiddle.net/4L8Ht/1/. In this case, I've added a blue border (same color of the rotated div).
HTML:
<div class="container">
<div class="rotateY r45deg"></div>
</div>
<div class="container">
<div class="rotateY r90deg"></div>
</div>
CSS:
.container {
width: 200px;
height: 200px;
margin: 50px;
border: 1px solid #ccc;
-webkit-perspective: 400;
}
.rotateY {
width: 100%;
height: 100%;
background-color: #00f;
border: 1px solid #00f;
}
.r45deg { -webkit-transform: rotateY(45deg); }
.r90deg { -webkit-transform: rotateY(90deg); }

How do I create a circle or square with just CSS - with a hollow center?

It should just basically be an outline of the square or circle - that I can style accordingly (i.e. change the color to whatever I want, change the thickness of the border, etc.)
I would like to apply that circle or square over something else (like an image or something) and the middle part should be hollowed out, so you can see the image beneath the square or circle.
I would prefer for it to be mainly CSS + HTML.
Try This
div.circle {
-moz-border-radius: 50px/50px;
-webkit-border-radius: 50px 50px;
border-radius: 50px/50px;
border: solid 21px #f00;
width: 50px;
height: 50px;
}
div.square {
border: solid 21px #f0f;
width: 50px;
height: 50px;
}
<div class="circle">
<img/>
</div>
<hr/>
<div class="square">
<img/>
</div>
More here
You can use special characters to make lots of shapes. Examples:
http://jsfiddle.net/martlark/jWh2N/2/
<table>
<tr>
<td>hollow square</td>
<td>□</td>
</tr>
<tr>
<td>solid circle</td>
<td>•</td>
</tr>
<tr>
<td>open circle</td>
<td>๐</td>
</tr>
</table>
Many more can be found here: HTML Special Characters
i don't know of a simple css(2.1 standard)-only solution for circles, but for squares you can do easily:
.squared {
border: 2px solid black;
}
then, use the following html code:
<img src="…" alt="an image " class="squared" />
If you want your div to keep it's circular shape even if you change its width/height (using js for instance) set the radius to 50%. Example:
css:
.circle {
border-radius: 50%/50%;
width: 50px;
height: 50px;
background: black;
}
html:
<div class="circle"></div>
Circle Time! :) Easy way of making a circle with a hollow center : use border-radius, give the element a border and no background so you can see through it :
div {
display: inline-block;
margin-left: 5px;
height: 100px;
border-radius: 100%;
width:100px;
border:solid black 2px;
}
body{
background:url('http://lorempixel.com/output/people-q-c-640-480-1.jpg');
background-size:cover;
}
<div></div>
To my knowledge there is no cross-browser compatible way to make a circle with CSS & HTML only.
For the square I guess you could make a div with a border and a z-index higher than what you are putting it over. I don't understand why you would need to do this, when you could just put a border on the image or "something" itself.
If anyone else knows how to make a circle that is cross browser compatible with CSS & HTML only, I would love to hear about it!
#Caspar Kleijne border-radius does not work in IE8 or below, not sure about 9.
Shortly after finding this questions I found these examples on CSS Tricks: http://css-tricks.com/examples/ShapesOfCSS/
Copied so you don't have to click
.square {
width: 100px;
height: 100px;
background: red;
}
.circle {
width: 100px;
height: 100px;
background: red;
-moz-border-radius: 50px;
-webkit-border-radius: 50px;
border-radius: 50px;
}
/* Cleaner, but slightly less support: use "50%" as value */
<div class="square"></div>
<div class="circle"></div>
There are many other shape examples in the above link, but you will have to test for browser compatibility.
In case of circle all you need is one div, but in case of hollow square you need to have 2 divs.
The divs are having a display of inline-block which you can change accordingly. Live Codepen link: Click Me
In case of circle all you need to change is the border properties and the dimensions(width and height) of circle. If you want to change color just change the border color of hollow-circle.
In case of the square background-color property needs to be changed depending upon the background of page or the element upon which you want to place the hollow-square. Always keep the inner-circle dimension small as compared to the hollow-square. If you want to change color just change the background-color of hollow-square. The inner-circle is centered upon the hollow-square using the position, top, left, transform properties just don't mess with them.
Code is as follows:
/* CSS Code */
.hollow-circle {
width: 4rem;
height: 4rem;
background-color: transparent;
border-radius: 50%;
display: inline-block;
/* Use this */
border-color: black;
border-width: 5px;
border-style: solid;
/* or */
/* Shorthand Property */
/* border: 5px solid #000; */
}
.hollow-square {
position: relative;
width: 4rem;
height: 4rem;
display: inline-block;
background-color: black;
}
.inner-circle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 3rem;
height: 3rem;
border-radius: 50%;
background-color: white;
}
<!-- HTML Code -->
<div class="hollow-circle">
</div>
<br/><br/><br/>
<div class="hollow-square">
<div class="inner-circle"></div>
</div>