I have bee trying to do a close button using CSS in order to close a tag.
I have done this using a compination of a pattern described here: Patterns for Closebuttons, and a css only pattern for creating an X Close Button using CSS.
Now to my question:
I can't figure out why the X is not entierly centered.
If I change the placement to 50% of whatever width I'm using for the lines it seemes fine, thus I come to the conclusion it has to have something to do with the width of the lines.
I'm writing here to see if someone could explain this to me.
'HTML
<button type="button" aria-label="Close">
<span aria-hidden="true" class="close"></span>
</button>
'CSS
button {
display: flex;
justify-content: center;
align-items: center;
font-weight: 700;
padding: 0px;
background-color: rgb(192,192,192);
border: none;
color: white;
text-decoration: none;
height: 150px;
width: 150px;
border-radius: 50%;
}
button:hover {
background-color: rgb(146, 146, 146);
cursor: pointer;
}
.close {
position: relative;
/* right: 10px; */
width: 60%;
height: 60%;
}
.close:before, .close:after {
position: absolute;
content: ' ';
height: 100%;
width: 20px;
background-color: rgb(255, 255, 255);
}
.close:before {
transform: rotate(45deg);
}
.close:after {
transform: rotate(-45deg);
}
I created a codepen for simplicity: Codepen link
Just add flexbox to the .close class and you're ready to go
.close {
position: relative;
width: 100%;
height: 60%; // 100% means that both lines will take the entire space
display: flex;
align-items: center;
justify-content: center;
}
The width of the .close:before, .close:after CSS rule is actually letting both lines "expand" horizontally, starting from the center.
But, as they are being rotated, their starting position is not the same as if they were not rotated, so that's why their alignment becomes non-centered. You can inspect the item and you will see that the actual box has an empty space, which is the "rotated width" empty space.
Consider a x = 0 coordinate (0px from CSS box left margin) which is the horizontal starting point of the CSS box; rotating elements will make content to start at x = ? (usually half of the content width)
You could solve this issue also by setting a negative margin-left with its value being half the width, but using flexbox will require much less maintenance (just imagine working with UI/UX guys telling you to change its dimensions)
Add This CSS left:50%; margin-left:-10px; on .close:before, .close:after
.close:before, .close:after {
position: absolute;
content: ' ';
height: 100%;
width: 20px;
background-color: rgb(255, 255, 255);
left:50%;
margin-left:-10px;
}
Hello there try to add this to your span class .close:
display: flex;
justify-content: center;
align-items: center;
You should not use right or left when your attribute is relative.
Related
I can't seem to work out how to get my input to take up the whole height of the parent div when its rotated (i.e. I want some one to be able to type as much text in as will fit in the parent div.
I've tried changing both the width and height values of the input to 100% and it doesn't help.
I have it working when the input is not rotated, so there must be some sort of trick I am missing?
HTML
.Yaxis-Label-Container {
grid-area: Yaxis-Label;
display: flex;
align-items: center;
justify-content: end;
width: 100px;
height: 1000px;
}
#yaxisLabel {
width: 100%;
height: 29px;
margin: 0 0 0 5px;
background: transparent;
color: #000000;
border: none;
outline: none;
font-size: 16px;
text-align: center;
transform: rotate(-90deg);
}
<div class="Yaxis-Label-Container" >
<input
type="text"
autocomplete="off"
placeholder="Yaxis"
id="yaxisLabel"
/>
</div>
I've ran into this problem as well. All you have to do is use viewport width(vw) and viewport height(vh)
input {
width: 100vw;
height: 100vh;
}
or just try using an id selector if for some reason that selector won't work
#input {
width: 100vw;
height: 100vh;
}
*You won't use 100vw and 100vh you'd have to adjust it to fit the div element, but I can't get it to work any other way.
With your html and css and rotating the div instead of the input it will become this css
.Yaxis-Label-Container {
border: 1px solid red; /*remove this line, for test only*/
grid-area: Yaxis-Label;
display: flex;
align-items: center; /* input will center in width 1000px */
width: 1000px;
height: 100px;
margin-top: calc(0.5 * (1000px - 100px)); /* half of width minus height */
transform: rotate(-90deg);
}
#yaxisLabel {
box-sizing: border-box;
width: 100%;
height: 29px;
margin: 0;
background: transparent;
color: #000000;
border: 1px solid transparent;
outline: none;
font-size: 16px;
text-align: center;
}
<div class="Yaxis-Label-Container" >
<input
type="text"
autocomplete="off"
placeholder="Yaxis"
id="yaxisLabel"
/>
</div>
In the end I did what bron suggested but found that the yaxis label appeared to be shifted to the left as a result of the rotation
Therefore I had to implement a javascript solution to fix its position on the x co-ordinate
I added a listener to the co-ordinates of the parent div. Everytime it moved (i.e. screen resize) I had to calculate the distance required needed to shift the label element left or right such that it appeared in the right place
I have a screen with 3 horizontally aligned main areas:
The sidebar (1) can be collapsed/hidden (to the left). When hidden, the freed-up space shall be given to the visualization (3) whilst the menus width (2) stays the same.
ATM I'm aligning the content like this:
Parent container of (1), (2) & (3): display: flex
(1): width: 260px;
(2): width: 293px;
(3): flex: 1;
When collapsed, I simply set width: 0 for the sidebar.
I know that I could simply animate/transition the width change or go about it by changing and animating/transition the left property or play with margins etc. but all those solutions I can think of trigger the browsers layout step (changing width, left, margin, ...) which I'd like to prevent since that leads to poor animation performance as explained here.
Ideally I'd like to stay with CSS transitions of properties which only trigger the browsers compose step like translate etc.
Unfortunately I can't think of a way to only use those "good" CSS properties and also meet my goal of redistributing the freed-up space from the hidden sidebar to the visualization (3).
Is it even possible to hide the sidebar animated to the left without triggering a re-layout but still redistribute the freed-up space? If not, how can this still be done performantly?
I imagine that this is a pretty common use case in web development, so links to according literature, blogs etc. are welcome as well!
I found a lot of examples on the web regarding animated hiding of sidebars but they either animate the width property or don't redistribute the freed up space to the remaining visible content (e.g. sidebars which are simply shown "above" the main content etc.), so none of the examples I found so far actually meet my described goals...
Please check the following HTML,JS,CSS snippet. You could change the actual widths of the elements to exactly match the ones you need.
Manipulating the width of the sidebar is not a problem. Performance is, as explained in the link you provided. On the finishing lines of this article it is written:
Performance matters to users. Web developers need to build apps that
react quickly and render smoothly. Google performance guru Paul Lewis
is here to help you destroy jank and create web apps that maintain 60
frames per second performance. You'll leave this course with the tools
you need to profile apps and identify the causes of jank. You'll
explore the browser's rendering pipeline and uncover patterns that
make it easy to build performant apps.
So you could re-create the logic of the below example by using Javascript requestAnimationFrame as shown here.
const side = document.querySelector('.side');
const sideToggle = document.querySelector('.sideToggle');
const main = document.querySelector('.main');
sideToggle.addEventListener('click', () => {
if (!sideToggle.classList.contains('active')) {
sideToggle.classList.add('active');
} else {
sideToggle.classList.remove('active');
}
if (!main.classList.contains('full')) {
main.classList.add('full');
} else {
main.classList.remove('full');
}
if (!side.classList.contains('hidden')) {
side.classList.add('hidden');
} else {
side.classList.remove('hidden');
}
});
.container {
display: inline-flex;
flex-direction: row;
align-items: stretch;
align-content: space-evenly;
justify-content: space-evenly;
width: 100%;
}
.side {
display: flex;
flex-direction: column;
align-items: stretch;
align-content: space-evenly;
justify-content: space-evenly;
background: #000;
padding: 0;
width: 20%;
height: 100vh;
transition: width 1s linear;
}
.side a {
color: #fff;
text-decoration: none;
line-height: 1;
height: 1.5rem;
padding: 1rem;
}
.side a:hover {
color: #000;
background: #fff;
}
.side.hidden {
width: 0;
transition: width 1s linear;
}
.sideToggle {
background: #000;
color: #fff;
width: 2rem;
height: 2rem;
position: fixed;
right: .75rem;
bottom: .75rem;
border-radius: 50%;
text-align: center;
cursor: pointer;
z-index: 1001;
}
.sideToggle:after {
content: "\2630";
font-size: 1.25rem;
vertical-align: top;
}
.sideToggle.active:after {
content: "\00D7";
vertical-align: top;
font-size: 1.75rem;
}
.main {
background: red;
width: 80%;
height: 100vh;
transition: width 1s linear;
display: inline-flex;
flex-direction: row;
align-items: stretch;
align-content: space-evenly;
justify-content: space-evenly;
width: 100%;
color: #fff;
}
.main.full {
width: 100%;
transition: width 1s linear;
}
.left {
width: 15rem;
padding: 1rem;
}
.right {
width: calc(100% - 15rem);
background: indigo;
padding: 1rem;
}
<div class="container">
<div class="side">
Home
Page 1
Page 2
Page 3
</div>
<span class="sideToggle active"></span>
<div class="main">
<div class="left">
this width is ment to be static
</div>
<div class="right">
this width is ment to be dynamic
</div>
</div>
</div>
This is another possible way by using mostly translateX and without changing the width of the sidebar.
const side = document.querySelector('.side');
const sideToggle = document.querySelector('.sideToggle');
const main = document.querySelector('.main');
sideToggle.addEventListener('click', () => {
if (!sideToggle.classList.contains('active')) {
sideToggle.classList.add('active');
} else {
sideToggle.classList.remove('active');
}
if (!main.classList.contains('full')) {
main.classList.add('full');
} else {
main.classList.remove('full');
}
if (!side.classList.contains('hidden')) {
side.classList.add('hidden');
} else {
side.classList.remove('hidden');
}
});
.container {
display: inline-flex;
flex-direction: row;
align-items: stretch;
align-content: space-evenly;
justify-content: space-evenly;
width: 100%;
}
.side {
display: flex;
flex-direction: column;
align-items: stretch;
align-content: space-evenly;
justify-content: space-evenly;
background: #000;
padding: 0;
width: 7rem;
transform: translateX(0);
height: 100vh;
transition: transform 1s linear, z-index 1s linear;
z-index: 9999;
position: fixed;
left: 0;
top: 0;
will-change: transform, z-index;
}
.side a {
color: #fff;
text-decoration: none;
line-height: 1;
height: 1.5rem;
padding: 1rem;
}
.side a:hover {
color: #000;
background: #fff;
}
.side.hidden {
transform: translateX(-100%);
transition: transform 1s linear, z-index 1s linear;
z-index: -1;
}
.sideToggle {
background: #000;
color: #fff;
width: 2rem;
height: 2rem;
position: fixed;
right: .75rem;
bottom: .75rem;
border-radius: 50%;
text-align: center;
cursor: pointer;
z-index: 1001;
}
.sideToggle:after {
content: "\2630";
font-size: 1.25rem;
vertical-align: top;
}
.sideToggle.active:after {
content: "\00D7";
vertical-align: top;
font-size: 1.75rem;
}
.main {
background: red;
width: calc(100% - 7rem);
height: 100vh;
transition: transform 1s linear, width 1s linear;
display: inline-flex;
flex-direction: row;
align-items: stretch;
align-content: space-evenly;
justify-content: space-evenly;
color: #fff;
left: 0;
top: 0;
transform: translateX(7rem);
position: absolute;
will-change: transform, width;
}
.main.full {
transform: translateX(0);
width: 100%;
transition: transform 1s linear, width 1s linear;
}
.main .left,
.main.full .left {
flex-grow: 1;
flex-shrink: 1;
width: 15rem;
padding: 1rem;
}
.right {
flex-grow: 2;
flex-shrink: 2;
width: calc(100% - 15rem);
background: indigo;
padding: 1rem;
}
<div class="container">
<div class="side">
Home
Page 1
Page 2
Page 3
</div>
<span class="sideToggle active"></span>
<div class="main">
<div class="left">
this width is ment to be static
</div>
<div class="right">
this width is ment to be dynamic
</div>
</div>
</div>
Althought the solution of user2560539 is nice, it did not suffice my requirements because with a lot of elements in the content area, the manipulation of the sidebar width leads definitely to a performance problem.
The issue is that as soon as you start transforming geometrical or positional properties (width, height, margin, padding, top, left, bottom, right, etc.) the browser starts to recalculate the layout again and again for every frame during the animation. You can see this in the performance tab of Chrome or Firefox as "Layout Shift". This is super laggy as soon as your DOM includes more than a few nodes.
Transformations (translations, rotations, skews, etc.) are much faster because the browser does not need to calculate all values regarding geometry and position over and over again. The browser calculates everything on a per pixel basis.
So I came up with another solution. What I did is to use the fast
transform: scaleX(1.1); //e.g. 1920px / 1745px
CSS property to enlarge the content area. The factor 1.1 is calculated by the width of the full content area (no sidebar visible) divided by the compressed content area (sidebar visible).
With this in mind you can use a simple translation animation to translate the sidebar and to scale the content area. Here is a codepen [slightly stolen from user2560539, thank you :) ]:
https://codepen.io/enne87/pen/MWBaOrp
Of course the content is distorted since scaleX does not only scale the content wrapper, but also all its child elements. If this is a problem for you, you can add a CSS class to the distorted elements which holds the inverse of the scaleX operation:
.make-thinner-initally {
transform: scaleX(0.9088); //e.g. 1745px / 1920px
}
Add this class to the elements as soon as the animation begins and remove it after the animation ends.
By the way, Google Calendar uses a very similar approach when you expand / collapse the left side bar.
I am attempting to tile a webpage with div elements of various sizes. However, I am running into an issue with once x number of div elements have filled the width of the screen the following div is placed below the previous 'row', rather than being floated to fit into space between elements in the previous 'row'. The code below better demonstrates what I mean; I'd like the 'game' div to be floated to fit into the space above where it is currently positioned.
h1 {
color: white;
}
.center {
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.container {
display: inline-block;
}
.default {
margin: 1em;
float: left;
}
/* For hover text */
.hover_img {
width: 100%;
height: 100%;
position: relative;
float: left;
}
.hover_img h4 {
color: white;
}
.hover_img:hover img {
opacity: .2;
}
.hover_img:hover .center_text {
display: block;
}
.center_text {
position: absolute;
top: 50%;
left: 0;
display: none;
font-weight: bold;
text-align: center;
}
img {
margin: 0;
}
.rectangle-tile-horizontal {
height: 15em;
width: 35em;
}
.red {
background-color: rgba(255, 63, 63, 0.8);
}
#game, #game img {
width: 30em;
height: 30em;
}
#app, #app img {
width: 40em;
height: 35em;
}
<div class="container">
<div class="rectangle-tile-horizontal red center default">
<h1><b>Projects</b></h1>
</div>
<div class="rectangle-tile-horizontal hover_img default" id="app">
<img src="http://cohenwoodworking.com/wp-content/uploads/2016/09/image-placeholder-500x500.jpg">
<div class="center_text"><h4>Web App</h4></div>
</div>
<div class="hover_img default" id="game">
<img src="http://cohenwoodworking.com/wp-content/uploads/2016/09/image-placeholder-500x500.jpg">
<div class="center_text"><h4>Breakout</h4> </div>
</div>
I'm afraid what you want to do is actually re-order your divs to create a space-filling layout. To the best of my knowledge, using only CSS for this is difficult, if not outright impossible.
I suggest you take a look at this SO post, or perhaps even the Bulma framework is what you want.
If, however, you move away from re-ordering the containers automagically and instead look towards a solution that elastically adapts the width of each container to fill the available space while maintaining its "order" (first, second, third), I am sure CSS will be a viable solution. If you require assistance, please use the search or ask anew.
Create a style for your div class or id like
.className
{display:inline;}
and use it in your each div
Hope this will help you
An example of this
http://jsfiddle.net/JDERf/
I want to display the notification count inside a circle but I don't want it to have a fixed width so the circle can expand when there is a bigger number/text inside the circle.
.circle {
height: 20px;
width: 20px;
line-height: 20px;
border-radius: 50%;
background-color: red;
color: white;
text-align: center;
}
<div class="circle">5</div>
<br>
<div class="circle">102</div>
See this CSS only solution. Set the same value of min-width and min-height for 1 digit number. Use a pseudo element for vertical alignment and to maintain the square shape. With border-radius applies to the container for the circle.
.circle {
display: inline-block;
border-radius: 50%;
min-width: 20px;
min-height: 20px;
padding: 5px;
background: red;
color: white;
text-align: center;
line-height: 1;
box-sizing: content-box;
white-space: nowrap;
}
.circle:before {
content: "";
display: inline-block;
vertical-align: middle;
padding-top: 100%;
height: 0;
}
.circle span {
display: inline-block;
vertical-align: middle;
}
<div class="circle"><span>8</span></div>
<div class="circle"><span>64</span></div>
<div class="circle"><span>512</span></div>
<div class="circle"><span>4096</span></div>
This is so hacky, but it seems to check out on all the major browsers' latest versions, so I'll post it anyway. The basic principle is that percent-based padding (even top and bottom padding) are relative to the width of the parent. Setting it to 100% with a width and height of 0 would theoretically mean that the height of the element would always be equal to the width. Combine that with a pseudo element and you don't even need to change the markup. I used flexbox to correct the centering of the content. It seems to work on the browsers I tested it on, but this is definitely dependent on recent versions because it uses flexbox and display:table. I also had to add a min-width to ensure it doesn't appear out of shape for too little of content.
.circle {
background-color: red;
color: white;
text-align: center;
position: relative;
border-radius: 50%;
min-width: 1.25em;
display: inline-flex;
align-items: center;
justify-content: center;
}
.circle:after {
content: '';
padding-top: 100%;
display:table;
}
<div class="circle">5</div>
<br>
<div class="circle">102</div>
<br>
<div class="circle">4298347918</div>
Simple CSS for circles that works almost ever:
.circle {
position: relative;
border-radius: 50%;
width: 100%;
height: auto;
padding-top: 100%;
}
The trick is that the padding top is calculated on the width so you can use it for makinh height equals width
Try using border-radius:50% and set max-width and height
Here is a quick example where you can see how to dynamically maintain a circle with css and js.
As Jagjit Singh pointed out here, you can achieve a circle using border-radius: 50%; instead of a fixed-pixel value.
Here's the page I'm working on: http://en08-phx.stablehost.com/~news/test.html
This is the code I'm using to center the div:
div {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 70%;
height: auto;
padding: 20px;
background-color:rgba(255, 255, 255, 0.2);
color: white;
text-align: center;
border-radius:5px;
border:2px solid rgba(255, 255, 255, 0.5);
}
Whenever I decrease the width of my browser or use a mobile phone, the top of the page starts to get cut off.
I want the div to be centered regardless of the size of the browser width. However, if the browser's height is too small, I'd prefer to just add a margin of 10px to the top/bottom and make sure all the text shows.
What exactly am I doing wrong here?
The issue with this positioning technique (top 50% minus translateY -50%) is that it aligns itself based its own height. When the viewport squishes the container taller than the viewport it remains centered with the top and bottom getting cut off. If you're able to use flexbox I recommend flexbox (http://caniuse.com/#search=flex).
Wrap the container you want always centered in another container such as centered-wrapper and apply flexbox to center it:
.centered-wrapper {
display: flex;
flex-direction: column;
justify-content: center;
min-height: 100%;
}
The min-height is very important here. If your div doesn't stretch to the page's height it'll fill and center its child. If it is then it'll just keep expanding avoiding the scenario that you have as well. If you're box is relative in height to the whole page then you'll also need to set the height of your page for this to work:
html,
body {
height: 100%;
}
You don't need any centering done to your centered div, just the visual styles.
Here's a sample of it in action: https://jsfiddle.net/vfc9n7p2/
body {
display: flex;
flex-direction: column;
justify-content: center;
}
div {
/* position: absolute; */
/* left: 50%; */
/* top: 50%; */
/* transform: translate(-50%, -50%); */
width: 70%;
height: auto;
padding: 20px;
background-color: rgba(255, 255, 255, 0.2);
color: white;
text-align: center;
border-radius: 5px;
border: 2px solid rgba(255, 255, 255, 0.5);
margin: 0 auto;
}
this will work fine for you.
<br clear="all">
This has worked for me. Just put this before your content element like div.