How to set absolute positionning in react component - css

i'm trying to create a custom button for my portfolio.
This button will be animated, the top part sliding in from left and the bottom part sliding in from right when hovered.
At the center of it will be the Category linked to this button.
Here an illustration :
How can i set my text in the center for every that i will create ? I can't use "position: absolute" property cause the reference would be the webpage and not the position where the custom component is declared...
Here my actual code :
CSS
const CatStyle = styled.div`
box-shadow: 0px 0px 2px 2px rgba(0,0,0,0.75);
height: 50px;
max-width: 150px;
background-color: white;
display: flex;
justify-content: center;
flex-direction: column;
cursor: pointer;
transition : background-color 0.5s ease-out;
:hover div{
display: flex;
}
.catContent {
position: relative;
align-self: center;
font-size: 1.5rem;
}
.topSlideAnimation {
display: none
height: 50%;
background-color: green;
}
.botSlideAnimation {
transition : background-color 0.5s ease-out;
display: none;
height: 50%;
background-color: blue;
}
`
JSX
const ButtonCat = (props) => (
<CatStyle>
<div className="topSlideAnimation"></div>
<div className="catContent">Hello</div>
<div className="botSlideAnimation"></div>
</CatStyle>
)

Not done any jsx so not sure what your catstyle tag would render, but if you can just render a button (or div), I would do the following
Make an outer container that is flex (for aligning text in center)
Make an inner container that is for the text (so you can position it relatively and add a z-index to it)
Add pseudo elements to your outer container for the animated bits (rather than having 2 empty divs)
* {
box-sizing: border-box;
}
.button {
display: inline-flex; /* make flex for centring */
justify-content: center; /* vertically centre */
align-items: center; /* horizontally centre */
position: relative; /* for adding absolute positioned children */
min-height: 50px; /* test value to show text is centred */
overflow: hidden; /* hide pseudo elements when not shown */
}
.button:before,
.button:after {
content: ''; /* make coloured animatable bits */
display: block;
height: 50%;
width: 100%;
position: absolute;
transition: all 1s ease-in;
z-index: 1;
}
.button:before {
top: 0;
right: 100%;
background: grey;
}
.button:hover:before {
right: 0;
}
.button:after {
top: 50%;
left: 100%;
background: darkgrey;
}
.button:hover:after {
left: 0;
}
.text {
position: relative; /* needs to have a higher z-index than the pseduo elements so text appears on top */
z-index: 2;
}
<button class="button"><span class="text">test content</span></button>

Related

is there a way to make this less text and less complicated?

started to learn HTML and CSS, I want 4 blocks, 2 centred and 1 on each side, left and right. And if resize the window the block distance between the outer and inner blocks varies and the borders never cut each other
this is the full css code, I have the feeling I did this way too complicated.. I mean it works but yeah..
section {
display: inline-block;
position: relative;
width: 100vw;
height: 100vw;
background-color: blue;
}
.hm {
display: inline-block;
position: fixed;
top: 50%;
padding: 20px;
margin: 20px;
border: 10px solid yellow;
width: 60px;
height: 60px;
transform: translateX(-25%); translate: 10px;
}
.hm0 {
display: inline-block;
position: fixed;
top: 50%;
left: 50%;
padding: 20px;
margin: 20px;
border: 10px solid red;
width: 60px;
height: 60px;
transform: translate(-20px);
}
.hm1 {
display: inline-block;
position: fixed;
top: 50%;
left: 50%;
padding: 20px;
margin: 20px;
border: 10px solid rgb(211, 208, 208);
width: 60px;
height: 60px;
transform: translate(-100%); translate: -20px;
}
.hm2 {
display: inline-block;
position: fixed;
top: 50%;
right: 0;
padding: 20px;
margin: 20px;
margin-left: auto;
margin-right: 0;
border: 10px solid rgb(255, 0, 225);
width: 60px;
height: 60px;
}
<body>
<section>
<div class="hm"></div>
<div class="hm0"></div>
<div class="hm1"></div>
<div class="hm2"></div>
</section>
</body>
I am not sure if this is what you are going for, but I have attempted to recreate it with Flexbox.
First, I wrapped the blocks that should be in the center in another div as follows:
<section>
<div class="hm box"> </div>
<div class="center">
<div class="hm0 box"> </div>
<div class="hm1 box"> </div>
</div>
<div class="hm2 box"></div>
</section>
I also added a class box that will contain the height and width of each box.
With that, I styled them like so:
section {
display: flex;
justify-content: space-between;
align-items: center;
width: 100vw;
height: 100vw;
background-color: blue;
}
.center {
display: flex;
}
.hm {
border: 10px solid yellow;
}
.hm0 {
border: 10px solid red;
}
.hm1 {
border: 10px solid rgb(211, 208, 208);
}
.hm2 {
border: 10px solid rgb(255, 0, 225);
}
.box {
width: 60px;
height: 60px
}
The most important styles concerning the layout are here:
section {
display: flex;
justify-content: space-between;
align-items: center;
width: 100vw;
height: 100vw;
background-color: blue;
}
display: flex;: aligns all blocks horizontally(except the blocks in the .center div, because they are not the section element direct children)
justify-content: space-between;: this pushes the first and last blocks to the edges of the section element, leaving the center div elements in the center.
align-items: center;: aligns all the horizontal blocks in the center of the section element.
Now since the blocks in the center div are not direct descendants of section element, I also used display:flex to align them horizontally:
.center {
display: flex;
}
To learn more about flexbox and its properties, check out flexboxfroggy
You can checkout the demo of the code here:
https://jsfiddle.net/stanulilic/s7oh4nv9/
To re-write your posted CSS in a more concise form leads us to the following, explanatory comments are in the CSS:
/* this is a personal style or affectation that I tend to list
CSS properties alphabetically, that way if you're looking to
see if a property is set I know where to find it, and if it's
not where I expect it to be I know it hasn't been set on that
element/selector. This is a personal style, it's not mandatory
it's probably not even 'best-practice,' but you'll help yourself
if you pick a particular approach and then stick with it: */
section {
background-color: blue;
display: inline-block;
height: 100vw;
position: relative;
width: 100vw;
}
/* the following selector matches the four <div> elements within the
<section> element, and the child combinator (the '>') prevents the
selector matching any <div> elements nested within those child
elements. This selector then applies all common CSS styles for all
the child elements, to avoid redeclarations: */
section > div {
/* all <div> elements have a 10px solid border, so here we apply
that border with the color set to 'transparent,' allowing us to
set the 'border-color' in the individual elements: */
border: 10px solid transparent;
display: inline-block;
height: 60px;
padding: 20px;
margin: 20px;
position: fixed;
top: 50%;
width: 60px;
}
.hm {
/* setting the border-color for this specific element: */
border-color: yellow;
/* the following translations were combined into one
'translate' declaration, using the calc() method:
transform: translateX(-25%);
translate: 10px;
*/
translate: calc(-25% + 10px);
}
.hm0 {
/* again, setting properties specific to the individual elements: */
border-color: red;
left: 50%;
translate: -20px;
}
.hm1 {
border-color: rgb(211, 208, 208);
left: 50%;
/* combining the two different translations into one single declaration
via translate: calc(...):
transform: translate(-100%);
translate: -20px;
*/
translate: calc(100% - 20px);
}
.hm2 {
border-color: rgb(255, 0, 225);
margin-left: auto;
margin-right: 0;
right: 0;
}
<section>
<div class="hm"></div>
<div class="hm0"></div>
<div class="hm1"></div>
<div class="hm2"></div>
</section>
JS Fiddle demo.
Things to learn from the above snippet/approach:
try to group all common styling together under one selector that can apply to the each element of a group as a whole, two
use the same properties to do the same thing; don't combine functions and properties such as – for example – transform: translate() (or translateX()) with translate,
if you find you're having to use a property/function and then use a different property/function to further adjust, consider looking for a way to combine the two adjustments into one (the calc() function being a much-used, and versatile, way of doing so),
try and adopt an approach of organising your code in such a way that it becomes easy and predictable to find a property-value pair in your code, particularly CSS, where it's incredibly easy to just add amendments or additions to the end of a rule-set.
Now, the above layout can be achieved more easily using either CSS flex layout, or CSS Grid.
First, flex-box:
/* a simple CSS reset, to ensure all browsers size elements the same way,
using the border-box algorithm, to include borders and padding in the
declared sizing: */
*,
::before,
::after {
box-sizing: border-box;
/* removing browser-default margins and padding: */
margin: 0;
padding: 0;
}
section {
/* here we align the items within the <section> to the
vertical center; align-items works on the cross-axis
which is perpendicular to the main-axis; the main-
axis default is 'row' (so horizontal), therefore by
default 'align-items' positions the flex-items (the
elements within the flex-box) on the vertical axis:*/
align-items: center;
background-color: blue;
block-size: 100vh;
/* specifying the flex-layout: */
display: flex;
/* positioning elements to the center on the main-axis,
horizontal by default: */
justify-content: center;
}
section > div {
/* ensures that the element's width and height are equal: */
aspect-ratio: 1;
/* defining the borders of all elements matched by the
selector: */
border: 10px solid transparent;
/* defining the block-size of the matched elements; this is
a CSS logical property, and in European languages - and
others descended from those languages - is equivalent to
'height'; and the previous use of 'aspect-ratio'
automatically sets the 'inline-size' (equivalent to 'width'
in European languages and their descendants): */
block-size: 60px;
padding: 20px;
}
.hm {
border-color: yellow;
/* to move this element as far as possible to the inline-start
(the left, for European languages) we use the following to
add an auto-sized margin to the inline-end (in European
languages that's the 'right') side: */
margin-inline-end: auto;
}
.hm0 {
border-color: red;
}
.hm1 {
border-color: rgb(211, 208, 208);
}
.hm2 {
border-color: rgb(255, 0, 225);
/* as above - for .hm - we want to move this element to the
inline-end (the 'right,' in European languages...) side,
so we again set an auto margin on the opposing side, the
'inline-start' ('left,' in European languages): */
margin-inline-start: auto;
}
<section>
<div class="hm"></div>
<div class="hm0"></div>
<div class="hm1"></div>
<div class="hm2"></div>
</section>
JS Fiddle demo.
And, finally, CSS Grid layout:
/* a simple CSS reset, to ensure all browsers size elements the same way,
using the border-box algorithm, to include borders and padding in the
declared sizing: */
*,
::before,
::after {
box-sizing: border-box;
/* removing browser-default margins and padding: */
margin: 0;
padding: 0;
}
section {
align-items: center;
background-color: blue;
block-size: 100vh;
/* specifying the flex-layout: */
display: grid;
grid-template-columns: repeat(4, 1fr);
}
section > div {
/* ensures that the element's width and height are equal: */
aspect-ratio: 1;
/* defining the borders of all elements matched by the
selector: */
border: 10px solid transparent;
/* defining the block-size of the matched elements; this is
a CSS logical property, and in European languages - and
others descended from those languages - is equivalent to
'height'; and the previous use of 'aspect-ratio'
automatically sets the 'inline-size' (equivalent to 'width'
in European languages and their descendants): */
block-size: 60px;
padding: 20px;
}
/* selecting the odd-numbered <div> elements within the <section>,
the first and third: */
section > div:nth-child(odd) {
/* positioning them to the inline-start by setting their
margin-inline-end (right, in European languages...) to
'auto': */
margin-inline-end: auto;
}
/* selecting the even-numbered <div> elements within the <section>,
the second and fourth: */
section > div:nth-child(even) {
/* positioning them to the inline-end, by setting the opposing
margin - margin-inline-start - to auto: */
margin-inline-start: auto;
}
.hm {
border-color: yellow;
}
.hm0 {
border-color: red;
}
.hm1 {
border-color: rgb(211, 208, 208);
}
.hm2 {
border-color: rgb(255, 0, 225);
}
<section>
<div class="hm"></div>
<div class="hm0"></div>
<div class="hm1"></div>
<div class="hm2"></div>
</section>
JS Fiddle demo.
References:
align-content.
align-items.
aspect-ratio.
background-color.
block-size.
border.
border-color.
box-sizing.
calc().
CSS Logical Properties.
display.
grid-template-columns.
height.
inline-size.
justify-content.
justify-items.
margin.
margin-block.
margin-block-end.
margin-block-start.
margin-inline.
margin-inline-end.
margin-inline-start.
padding.
padding-block.
padding-block-end.
padding-block-start`.
padding-inline-end.
padding-inline-start.
place-items.
repeat().
transform.
translate (CSS property).
translate() (CSS function).
width.

Is it possible not to use absolute position?

I want to add animation to the button with the following code https://codepen.io/chrisota/pen/bNdRaM
but altered it a bit like this
a::before{
position: absolute;
top: 0;
bottom: 0;
margin: auto;
content:'';
border-radius: 50%;
display: block;
width: 30px*2;
height: 20px*2;
line-height: 30px*2;
left: -30px/2;
text-align: center;
transition: box-shadow 0.5s ease-out;
z-index: -1;
}
a:hover{
color: #fff;}
a:hover::before{
box-shadow:inset 0 0 0 $width rgba($button-color,1);
}
However,as far as I know absolute position is better not to use, but when I delete it, the button vanishes
<row>
<div class='col-5'>
a(href="http://www.dribbble.com/chrisota" title="Chris Ota Dribbble") <i class="fa fa-dribbble"></i> Dribbble
</div>
</row>
position: absolute is a wonderful tool when wielded properly.
It truly shines in the ::before and ::after psuedo-elements.
When you set the position of the element to relative and the position of ::before and ::after to absolute, you can position your pseudo-elements relative to the element itself.
This allows you to do cool things like adding icons to your buttons for example.
Just make sure to set the display and content properties like below. You can add the top, right, bottom, and left properties to move the element around.
.some-class {
position: relative;
}
.some-class::before {
position: absolute;
display: block;
content: '';
top: 10px; /* just an example */
left: 10px; /* just an example */
width: 32px; /* just an example */
height: 32px; /* just an example */
}

Different alignment of ::after pseudo element in a flex-box in Safari

While implementing a simple toggle control I encountered a problem that only seems to appear in Safari. The same code works fine in Firefox and Chrome.
.mgs.huge {
font-size: 36pt;
}
input.mgs.toggle {
display: none;
}
label.mgs.toggle {
display: flex;
flex-direction: row;
align-items: center;
width: max-content;
position: relative;
--toggle-color: 49, 112, 212;
}
/* The toggle background. */
label.mgs.toggle::before {
display: inline-block;
content: "";
height: 12px;
width: 23px;
border: 1px solid rgba(var(--toggle-color), 1);
background-color: rgba(var(--toggle-color), 0.75);
border-radius: 25pt;
margin-right: 4px;
}
label.mgs.toggle.huge::before {
height: 35px;
width: 69px;
}
/* The circle (handle) in the toggle - unchecked, standard size. */
label.mgs.toggle::after {
flex: 0 0 auto;
align-self: center;
content: "";
position: absolute;
width: 12px;
height: 12px;
left: 1px;
background-color: white;
border-radius: 50%;
transition: left 0.2s;
}
label.mgs.toggle.huge::after {
width: 35px;
height: 35px;
}
input:checked.mgs.toggle.huge + label::after {
left: 35px;
}
<input type="checkbox" class="mgs toggle huge" readonly="" id="toggle6" value="">
<label for="toggle6" class="mgs toggle huge">Huge</label>
In Safari the white knob doesn't align vertically. By specifying a top value you can align it manually (in this case by adding 11px top to label.mgs.toggle.huge::after), but unfortunately this shows another problem: Firefox doesn't use the same vertical offset as Chrome and Safari do: the circle is offset subtly by half a pixel or so.
Hence I would prefer a solution where Safari does the automatic vertical centering, as it is supposed in this flex-box layout.
Here's also a fiddle to play with: https://jsfiddle.net/3Ltkwaux/.

Unwanted effect with CSS animation hover happening a second time on each child

When applying a CSS transform based on a hover for my element which contains a title a summary and some other elements, all the children elements would move a second time when I hover over them inside the element.
Basically, the parent and its children(title, highlight...) will be animated a first time when I hover over it. (this is the intended behaviour).
But, if I hover over the title, it will apply the animation to the title individually, a second time. So, the title would be transformed a first time, let's say going up by 10px, and when I hover over it, it will go up again by 10 other pixels. The outer div (parent) will move only once. (Unwanted)
It is like I have applied their own animations to the parent and each one of the children.
I tried to apply transform: none; to all the children elements, but, it does not help in my case.
CSS:
.badge {
flex-basis: 50%;
transform: translateY(0);
transition-duration: 1s;
transition-property: transform;
transition-timing-function: ease-out;
transition-delay: 1s;
backface-visibility: hidden;
}
.badge:last-child {
flex-basis: 100%;
}
.badge :hover {
transform: translateY(-8px);
}
.badge__badge {
margin-bottom: 40px;
margin-right: 40px;
width: 99%;
height: 200px;
background-color: rgb(27, 139, 45);
border-radius: 8px;
color: aliceblue;
box-shadow: 0 4px 2px -2px rgba(0,0,0,0.4);
}
.badge__prime {
margin-left: 20px;
margin-right: auto;
}
.badge__content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
}
.badge__icon {
width: 40px;
height: auto;
margin: 10px;
}
.badge__highlight {
margin-right: auto;
margin-left: 30px;
display: flex;
flex-direction: column;
}
JSX (React):
<div className="badge">
<div className="badge__badge"
style={{ backgroundColor: this.props.backgroundColor }}>
<div className="badge__content">
{this.props.prime ? <h4 className="badge__prime">PRIME</h4>
: <h4 className="badge__prime">Free</h4>}
<h2 className="badge__title">{this.props.titleBadge}</h2>
<div className="badge__highlight">
{this.props.highlightBadge.split('\n').map((i, key) => {
return <div key={key}>{i}</div>;
})}
</div>
</div>
<img className="badge__icon"alt="" src={this.props.iconBadge} />
</div>
</div>
Expected results: the parent div and all its children will animate once on hover and will come back to their state once the mouse is outside of the div.
Actual results: The parent div and all its children animate once on hover, and the children will animate again if the mouse is over one of them.
Link to a jsfiddle that shows my issue

Changing a span' location depending on different span

Inside my Pen you can see an image block with a title on the bottom. When the user hovers over the block, a description is shown on the bottom and the title is moved.
However, the title is on the correct location if the description contains 1 line of text. With 2 lines of text, the title is on top the description. How could I have the title always just above the description, without moving it all the way to the top of the block?
.trend-block {
position: relative;
width: 150px;
height: 150px;
&:hover {
.transition-title {
bottom: 35px;
}
.trend-text {
display: inline-block;
width: 120px;
color: red;
position: absolute;
bottom: 15px;
padding: 0 15px;
}
}
}
.trend-image {
width: 100%;
height: 100%;
}
.trend-title {
font-weight: bold;
color: red;
position: absolute;
bottom: 15px;
padding: 0 15px;
}
.trend-text {
display: none;
}
.transition-title {
transition: bottom .1s ease;
}
You could make a wrapper class absolute instead of the two spans (.trend-content); https://codepen.io/anon/pen/jxxbpx. The .trend-text does now have a max-height of zero as default. When you hover over it, the max-height will be te same as te container (Can't be a height of auto in order to make the transition).

Resources