How to place something in a triangle-shaped box? - css

I found various examples of how to create triangles using CSS (like this one); all of them are based on creating a 0-sized box and fiddling with borders to create the triangle shape. Ok, very nice.
But how can I actually place something inside such a triangle?

You can use positioning techniques to place some content over the triangle and not under the triangle..
I emphasized over and under because using positioning am positioning the text over the triangle, so triangle element isn't the parent of the content, as to create triangles we use height: 0; and width: 0; so you need to overlay the text.
Just make sure you use position: relative; for parent element holding absolute positioned element.
Didn't used z-index but you can use that to play safe with the stacking order.
Demo
<div class="wrap">
<div class="triangle"></div>
<span>Hello</span>
</div>
div.wrap {
position: relative;
}
div.triangle {
height: 0;
width: 0;
border: 50px solid #f00;
border-top-color: transparent;
border-left-color: transparent;
border-right-color: transparent;
}
div span {
position: absolute;
left: 35px;
bottom: 0;
}

This way can be sloppy but it would work for a basic situation.
http://jsfiddle.net/Yc5nF/1/
<div class="arrow-right">
<p>Foobar</p>
</div>
.arrow-right {
position: relative;
width: 0;
height: 0;
border-left: 150px solid transparent;
border-bottom: 150px solid green;
border-right: 150px solid transparent;
}
.arrow-right p {
position: absolute;
top: 70px;
left: -20px;
}

Related

outline to only one side of div

I have tried few but is there a way to create an outline to right side of the div?
somthing like the purple line in the below image
https://unsee.cc/geduzopi/
use a pseudo element absolutely positioned to the right of the parent, then use translateX() to push it outside of the parent.
div {
display: inline-block;
width: 5em;
background: orange;
text-align: center;
position: relative;
}
div:after {
content: '';
width: .5em;
background: purple;
position: absolute;
right: 0; top: 0; bottom: 0;
transform: translateX(200%);
<div>1</div>
You can use border-right. For example
border-right: aqua 2pt solid;
See
https://www.w3schools.com/cssref/pr_border-right.asp
If you want to create an outline on one side and NOT a border, you can use box-shadow with inset like I did in my codepen example below. My example is good to look at if you have a border radius.
https://codepen.io/drewkiimon/pen/qeWQVx
div {
background: pink;
height: 250px;
width: 250px;
box-shadow: inset 0 1px black;
}
<div>
</div>

how to achieve following overlay while keeping it responsive

I am trying to achieve white overlay that can be seen above. image behind it is a slideshow and I need to show little bit of it with that triangle cut out in the middle, I'm trying to figure out a way of how to achieve this with pseudo elements while keeping solution responsive at the same time, but cant seem to find a way. I was also thinking about using multiple backgrounds, but am not sure how to make one of them in the centre and other two on the sides.
<div id="slideshow"></div>
Above is markup for slideshow at the moment (slides appear as background images of this div, it is absolutely positioned).
Utilizing some pseudo class before and afters on the center container, you can create CSS triangles using CSS borders.
See this for CSS triangles : https://css-tricks.com/snippets/css/css-triangle/
Technically you wouldn't need to use the before/after for the containers but I used it here anyways to keep the mark-up clean.
Next using some positioning and some width calculations, I set the two containers (left and right) to width 40% which leaves me 20% to play around with for the center section.
Lastly using, vw units, I set the border-left and border-right sizes to be 10vw. This is important because it basically allows the borders to be responsive based on the viewport width as long as the slideshow is full width.
See the JSFiddle here (Updated) : https://jsfiddle.net/x117ss0q/4/
<div id="slideshow">
<div class="slideshow-overlay-wrapper">
<div class="slideshow-overlay left"></div>
<div class="slideshow-overlay-center"></div>
<div class="slideshow-overlay right"></div>
</div>
</div>
#slideshow{
background-color: #333;
position: relative;
height: 200px;
}
.slideshow-overlay-wrapper {
bottom: 0;
display: table;
left: 0;
position: absolute;
width: 100%;
table-layout: fixed;
}
.slideshow-overlay {
background-color: #fff;
display: table-cell;
height: 50px;
}
.slideshow-overlay-center {
display: table-cell;
height: 50px;
width: 200px;
position: relative;
}
.slideshow-overlay-center:after {
content: '';
left: 0;
position: absolute;
border-bottom: 0px solid transparent;
border-top: 50px solid transparent;
border-left: 100px solid #FFF;
width: 0;
height: 0;
}
.slideshow-overlay-center:before {
content: '';
right: 0;
position: absolute;
border-bottom: 0px solid transparent;
border-top: 50px solid transparent;
border-right: 100px solid #FFF;
width: 0;
height: 0;
}

Control which border position sets the corner pixels in CSS

Imagine the following CSS:
#foo {
border: 1px solid black;
border-right: 1px solid blue;
}
In this case, at least under Chrome, the top and bottom right corner pixels of the element are blue, not black. Is it possible to make them black?
You can't do it with the normal CSS border options, but if you want to, you can still have a pure CSS solution:
Basically, what you are going to do is create two pseudo elements with CSS, and cover the corners:
#foo {
border: 100px solid black;
border-right: 100px solid blue;
height:300px;
position:relative;
}
#foo:after, #foo:before{
content:'';
background:black;
width:100px;
height:100px;
display:block;
position:absolute;
}
#foo:after{
bottom:-100px;
right:-100px;
}
#foo:before{
top:-100px;
right:-100px;
}
It might be a little messy, but it works. Set the :after and :before elements width height and position to the width of the border.
And that gives this effect:
JSFiddle Demo
I hope my crappy photoshop skills explain borders to you.
If you look in the 4 corners of the square you can see little lines, thats where one border starts and the next one begins.
This will always be in issue :P
You could either make it a background image (crappy way)
or you can use other divs to make the borders (crappy as well)
The first solution would be using a pseudo-element, which you will position absolutely to cover the right border. In order to ensure that it covers the border entirely, you will have to offset its top, bottom and right positions by the negative value of the border width. In this case I have used a width of 5px to better illustrate the example:
#foo {
background-color: #eee;
border: 5px solid grey;
width: 100px;
height: 100px;
position: relative;
}
#foo::before {
content: '';
position: absolute;
top: -5px;
bottom: -5px;
right: -5px; /* move by border width */
background-color: blue;
width: 5px;
}
<div id="foo"></div>
Alternatively, you can use CSS box shadow:
#foo {
background-color: #eee;
box-shadow: inset 0 0 0 5px grey;
width: 100px;
height: 100px;
position: relative;
}
#foo::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
right: 0;
width: 5px;
background-color: blue;
}
<div id="foo"></div>
As others have pointed out, your problem is how borders are drawn in CSS.
<div id="foo">Problem</div>
#foo {
border: 30px solid black;
border-right: 30px solid blue;
}
The simplest way to work around this is to use a pseudo element. Since this workaround is entirely dependent on the value of the border-width, I’ll show an example using an SCSS variable to help make it clear where that width value is coming in.
Note: You don’t need SCSS to solve this problem, using a variable just helps readability/maintainability.
HTML:
<div id="foo"></div>
SCSS:
/* Set SCSS variable */
$border-width: 30px;
#foo {
border: $border-width solid black;
position: relative; /* anchor the absolute positioned ::after element */
}
#foo:after {
content: '';
background: blue;
width: $border-width;
height: 100%;
position: absolute;
right: -$border-width;
}
Demo: http://jsbin.com/cimaxe/6
Hopefully it’s clear that everywhere you see $border-width you can replace it with a value like 30px.

CSS Border with a botton

Can I achieve a custom CSS border with a button at one end which looks like this
Without url(some image link)?
Note: I want so because when I want to change color, I have to manipulate image.
I have achieved using image JS Fiddle
#stretch {
border-image: url(http://akitech.org/img/border.png) 30 30 stretch;
}
The easiest way is to use CSS pseudo-elements to create the decoration (the circle at the left) and to mask the chamfer at the right of the border (the angle at which the border-right would otherwise meet):
div {
border: 10px solid transparent;
width: 250px;
padding: 10px 20px;
position: relative;
/* this property has to be set to change the border-color: */
border-bottom-color: #f90;
}
/* common shared styles: */
div::before,
div::after {
/* to ensure the pseudo-elements are rendered: */
content: '';
/* for positioning: */
position: absolute;
/* positioning the element with its uppermost edge
against the bottom of the element, against the
upper side of the bottom-border: */
top: 100%;
/* again, set to change the color of the ends: */
background-color: #f90;
}
div::before {
/* position against the left edge: */
left: 0;
/* move the pseudo element 10px up, and
10px left: */
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
/* making the pseudo-element a circle: */
border-radius: 50%;
}
/* masking the chamfer of the border-bottom's
right-most edge: */
div::after {
left: 100%;
/* making the height/width the same width
as the border itself: */
height: 10px;
width: 10px;
}
div {
border: 10px solid transparent;
width: 250px;
padding: 10px 20px;
position: relative;
border-bottom-color: #f90;
}
div::before,
div::after {
content: '';
position: absolute;
top: 100%;
background-color: #f90;
}
div::before {
left: 0;
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
div::after {
left: 100%;
height: 10px;
width: 10px;
}
<div id="stretch">Here, the image is stretched to fill the area.</div>
In order to have these borders adapt to the length of the text, either the elements you want to have custom-bordered must themselves be able to contract to the width of the text, either using float:
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
/* forces the element to take up only that space required by
its (non-floated) contents: */
float: left;
/* forces the floated elements to the next line: */
clear: left;
}
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
float: left;
clear: left;
}
div::before,
div::after {
content: '';
position: absolute;
top: 100%;
background-color: #f90;
}
div::before {
left: 0;
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
div::after {
left: 100%;
height: 10px;
width: 10px;
}
<div>text</div>
<div>longer text</div>
<div>much longer text</div>
<div>much much much longer text</div>
Or, possibly more simply, use display: inline-block:
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
display: inline-block;
}
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
display: inline-block;
}
div::before,
div::after {
content: '';
position: absolute;
top: 100%;
background-color: #f90;
}
div::before {
left: 0;
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
div::after {
left: 100%;
height: 10px;
width: 10px;
}
<div>text</div>
<div>longer text</div>
<div>much longer text</div>
<div>much much much longer text</div>
Or display: inline (these don't automatically force new-lines between elements, obviously):
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
display: inline;
}
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
display: inline;
}
div::before,
div::after {
content: '';
position: absolute;
top: 100%;
background-color: #f90;
}
div::before {
left: 0;
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
div::after {
left: 100%;
height: 10px;
width: 10px;
}
<div>text</div>
<div>longer text</div>
<div>much longer text</div>
<div>much much much longer text</div>
summary:
for simplist way to this question, should not using svg, pure css can draw the shape author expected very well cause it's a combination of cycle(border radius)+rect(thicker line), let's refer to the David's answer should be the easiest and most clean way to draw that shape under text.
//below is my debugging history and tries (i searched out many ways to approach it);
//though not good answers
I use background css attribute (not OP wanted) Op used border-image also valid.
<div class="custom-border" >SOME TEXT HERE</div>
<style>
.custom-border{
padding-left:20px;
width:200px;
background:url(http://img1.wikia.nocookie.net/__cb20140224040010/shantae/images/b/bc/HGH_border_bottom.png) 0px 5px no-repeat;
background-size:contain;
height:150px;
}
</style>
later I realized OP might dislike using image traditional way, I re understand the
question is asking how to draw that shape in pure css and place it under the text and the responsive should be as flexible as the traditional way the svg shape will auto strech with the text placed on it.
after that, I've find some way to generate svg and place under text
see if it works for no image solution or you can get it improved based on fiddle
http://jsfiddle.net/hahatey/hsfxS/1464/
during the process, i've found this useful tool of generating svg from below reference url: http://svg-edit.googlecode.com/svn/branches/2.6/editor/svg-editor.html
But the flaw is it's still a fixed width solution, the line svg won't auto stretch.
Have found a unclean way to improve auto stretch though not in pure css responsive way.
but auto strech can be done by dynamically change below line
<rect stroke="#ff0000" id="svg_2" height="8" width="100%" y="27" x="40" stroke-width="5" fill="#FF0000"/>
where width="100%" or fixed value => width="function return value"; //
// during this try, i found a little bug, jquery seems unable to select svg or element inside svg? however svg element tag attribute can be written in backend languge so still valid.
//3.44
Another way without touching the inner "rect' element below "svg" tag, is to add a container to the whole thing, and using function to dynamically
assign width for the container;
like my attempt in this
fiddle: http://jsfiddle.net/hahatey/hsfxS/1468/
so at least the width can be dynamically calculated out by a function to calculate the text length of the upper text so the line will be able to strech if the calculation is accurate enough. There could be other ways to do svg auto strech with the text using pure css if other ppl find it.
Thanks.
5.02// since the author didn't say how complex the content is inside the container,
I've created a demo in pure css triggered effct --- auto strech the shape along with the text above it in below fiddle. but i said it sure has many limitations though looks similar.
http://jsfiddle.net/hahatey/a9z1kyx7/
my upper fiddle is only able to align correctly for singleline auto strech
I'm wondering if complex content (more than one line, there maybe a lot of block,inline mixed tag element inside which increases complexity for alignment) can also use css to do such decoration width auto adjustment without touching javascript or backend language.

How to change content flow?

In this jsfiddle, I'm trying to create a bookmark shape. There is only one triangle which needs to change its positioning.
<div id = "bookmark">
<div id = "rectangle"></div>
<div id = "triangle-topleft"></div>
<div id = "triangle-topright"></div>
</div>
I could easily use relative positioning and shift it, but I don't want to do it this way. I want a more malleable solution.
Instead of the shapes flowing from top to bottom. I want the last shape to flow left to right. So there are 3 shapes, the first two are in the perfect place, but the third one needs to be placed to the right of the second shape, instead of underneath it.
What CSS can I use to do this?
Add float:left; to #triangle-topleft and margin-left:100px; to #triangle-topright
#triangle-topleft {
position: static;
width: 0;
height: 0;
border-top: 100px solid black;
border-right: 100px solid transparent;
float:left;
}
#triangle-topright {
position: relative;
width: 0;
height: 0;
border-top: 100px solid black;
border-left: 100px solid transparent;
margin-left:100px;
}
jsFiddle example
First of all you do not have to declare position: static; as it is already static by default (Unless you are using responsive design where you need to reset the property value at certain point of resolution), secondly, assign position: relative; to your #bookmark and make the second triangle position: absolute;
Demo
#bookmark{
width: 200px;
position: relative;
}
#rectangle {
width: 200px;
height: 300px;
background: black;
}
#triangle-topleft {
width: 0;
height: 0;
border-top: 100px solid black;
border-right: 100px solid transparent;
}
#triangle-topright {
position: absolute;
right: 0;
width: 0;
height: 0;
border-top: 100px solid black;
border-left: 100px solid transparent;
bottom: 0;
}
Note: Make sure you do not make your first triangle position: absolute; else you need to reposition the triangles. But this is the best method you can get, as you've wrapped absolute inside a relative container.
You can also take a look at this awesome thing - Font Awesome - Bookmark, you can resize this to whatever size you want to.
The thing you are trying can be also achieved by using :before and :after pseudo along with content property. So you can get rid of the extra triangle elements.
As I said, you can create this thing with a single element.
#bookmark{
width: 200px;
position: relative;
height: 300px;
background: black;
}
#bookmark:before {
width: 0;
height: 0;
border-top: 100px solid black;
border-right: 100px solid transparent;
display: block;
content: "";
position: absolute;
bottom: -100px;
}
#bookmark:after {
position: absolute;
right: 0;
width: 0;
height: 0;
border-top: 100px solid black;
border-left: 100px solid transparent;
bottom: -100px;
display: block;
content: "";
}
Here, am using :before and :after pseudo, with display: block; and content: ""; which are essential to get this thing work, also am positioning both the elements using absolute with a value set to -100
Demo (Using single element)
Note: :before and :after pseudo can fail in older versions of IE,
but you can always use polyfills to use CSS 3 properties, also, for
more information on browser support, you can check this out.
You can just add float: left to #triangle-topleft and margin-left: 100px to #triangle-topright.
To remove unnecessary markup, you could also use :before and :after pseudo-elements instead of #triangle-*.
Add display:inline-block to both triangle shapes. They're stacking because they are defaulting to display:block.
It suffices to just add float:left to #triangle-topleft and #triangle-topright.
See the fiddle: http://jsfiddle.net/nfxYE/

Resources