Search code examples
cssreactjspositionstyled-components

Fixed space between elements with CSS


I have a Label element with some text and a Span inside. The text of the label changes on user click (it gets shorter/larger). If i put a margin left in the span then when the text of the label gets shorter/larger the span moves with it. I want the span to be static, no matter if the element sitting besides it gets shorter/larger. For some reason i dont know (i am a bit noob with css) position the span with absolute does the work (if you can explain to me why is that it would be great). It's there a more efficient way of doing that? Should i still be using absolute/relative positioning having Flexbox and CSS Grid? Do not pay attention to the <Wrapper> component. That is just a HOC that returns its children to avoid putting everything inside a <div>.

import React, { useState } from 'react';
import styled from 'styled-components';
import Wrapper from '../HOCs/Wrapper';

const ToggleCheckbox = styled.input`
  display: none;
`;

const ToggleLabel = styled.label`
  cursor: pointer;
  padding: 2rem;
  display: inline-block;
  font-size: 1.6rem;
`;

const ToggleSpanBackground = styled.span`
  background-color: #e3dede;
  border-radius: 100px;
  display: inline-block;
  width: 40px;
  height: 10px;
  position: absolute;
  left: 14rem;
  top: 2.5rem;
  cursor: pointer;

  ${ToggleCheckbox}:checked + ${ToggleLabel} & {
    background-color: #2b90d9;
  }
`;

const ToggleSpanButton = styled.span`
  width: 2rem;
  height: 2rem;
  border-radius: 50px;
  display: inline-block;
  background-color: #e3dede;
  position: absolute;
  top: -0.5rem;
  left: 0.3rem;

  ${ToggleCheckbox}:checked + ${ToggleLabel} ${ToggleSpanBackground} &  {
    background-color: #2b90d9;
    left: 1.8rem;
  }
`;

export default function Toggle(props) {
  let [toggle, setToggle] = useState('off');

  return (
    <Wrapper>
      <ToggleCheckbox type='checkbox' id='toggle-checkbox'></ToggleCheckbox>
      <ToggleLabel
        htmlFor='toggle-checkbox'
        onClick={() =>
          setToggle((prevState) => {
            if (prevState === 'off') {
              return 'on';
            } else {
              return 'off';
            }
          })
        }
      >
        option: {toggle}
        <ToggleSpanBackground>
          <ToggleSpanButton></ToggleSpanButton>
        </ToggleSpanBackground>
      </ToggleLabel>
    </Wrapper>
  );
}

enter image description here


Solution

  • Well, position absolute effectively takes the element out of the DOM flow. So the thing getting bigger is not touching it any more so when it gets bigger it does not affect its position.

    I would make the span have a fixed width, a width big enough for a long or short value.