Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I fix the position of an input so it's always below an element that's centered on the screen but its size can change?

I have an element in my UI called a SkyElement, which is always vertically and horizontally centered in my UI. I also have an input, called a PencilInput that's I want to always be below the SkyElement.

In the UI, the user has the ability to change the size (width and height) of the SkyElement and I want the PencilInput to be positioned below the SkyElement, regardless of size.

Right now, the PencilInput is displaying above the SkyElement, regardless of size.

In my render function:

<div className="left-side">
    <SkyElement />

    <PencilInput />
</div>

The HTML of PencilInput:

<div className='pencil-input-holder'>
    <div className='pencil-svg' />

    <input className='pencil-input' onChange={this.handleChange} value={this.state.title} />
</div>

In my css:

@mixin absolute-center {
    display: block;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

.left-side {
    background: linear-gradient(180deg, #000000 0%, #205F8A 45.56%, #8852BB 100%);
    position: relative;

    .element {
        @include absolute-center;
        transform: scale(1.3);
        transform-origin: center center;
    }
}

.pencil-input-holder {
    border-bottom: 4px dashed rgba(255, 255, 255, 0.3);
    width: 50%;
    margin: 0 auto;

    .pencil-svg {
        background: url('../images/pencil.svg') center center no-repeat;
        width: 27px;
        height: 39px;
        display: inline-block;
        position: relative;
        top: 60px;
        left: 20px;
    }
}

input.pencil-input {
    position: relative;
    font-family: 'GT America Compressed Regular';
    text-align: center;
    font-size: 59px;
    color: rgba(255, 255, 255, 0.5);
    background: transparent;
    left: 50%;
    transform: translateX(-50%);
    border: none;

    &:focus { outline: none; }
}

Any help would be appreciated. Thanks!

Edit: Added render() block of SkyElement

Aside from the code below and the .left-side .element code above, that's the entirety of the css for the SkyElement

render() {
    const { connectDragSource, isDragging, hideSourceOnDrag, transformElement, top, left } = this.props;

    // hide on drag in slot view
    if (isDragging && hideSourceOnDrag) {
        return null;
    }

    const halfSize = this.props.size / 2;
    const transform = transformElement ? `translate(-50%, -50%)` : '';

    const style = {
        width: `${this.props.size}px`,
        height: `${this.props.size}px`,
        borderRadius: '50%',
        background: this.radialGradient(),
        opacity: isDragging ? 0.2 : this.props.opacity,
        boxShadow: this.boxShadow(),
        transform,
        transition: 'background 0.2s',
        position: 'relative',
        top,
        left,
    };

    return connectDragSource(
        <div onClick={this.editElement} className='element' style={style}>
            {
                this.props.labelPosition
                    ? <ElementLabel title={this.props.title} position={this.props.labelPosition } />
                    : null
            }
        </div>
    );
}
like image 709
Zack Shapiro Avatar asked Jul 24 '17 15:07

Zack Shapiro


2 Answers

One issue I see with your current solution, your @mixin is setup incorrectly. It produces 2 transform properties, which results in only one being applied:

transform: translate(-50%, -50%);
transform: scale(1.3);

This should be written as:

transform: translate(-50%, -50%) scale(1.3);

However, that is not the only issue. My recommendation would be to wrap the <SkyElement/> and <PencilInput/> in a wrapper component/element to center the group of elements horizontally/vertically.

<div className="left-side">
  <CenterElements>
    <SkyElement />
    <PencilInput />
  </CenterElements>
</div>

or

<div className="left-side">
  <div class="center">
    <SkyElement />
    <PencilInput />
  </div>
</div>

This element/component will contain the styles to horizontally and vertically center it.

I've attempted to use the existing CSS to show how this could be done. This will need to be converted back into Sass if you prefer that. The basic idea is to wrap the <SkyElement/> and <PencilInput/> in a wrapper element and center that vertically. You can then position the .pencil-input-holder element using position: absolute; within that. The <SkyElement/>'s size will not effect the size of the <PencilInput/> element with this implementation.

Something along these lines:

html,
body {
  height: 100%;
  min-height: 100%;
}
.left-side {
  background: linear-gradient(180deg, #000000 0%, #205F8A 45.56%, #8852BB 100%);
  position: relative;
  height: 100%;
  width: 100%;
}

.element-container {
  position: relative;
  width: 100%;
  top: 50%;
  transform: translateY(-50%);
  text-align: center;
}

.left-side .element {
  display: inline-block;
  height: 80px;
  width: 80px;
  line-height: 80px;
  text-align: center;
  border-radius: 50%;
  background-color: rgba(255,255,255, 0.5);
}

.pencil-input-holder {
  border-bottom: 4px dashed rgba(255, 255, 255, 0.3);
  width: 50%;
  position: absolute;
  margin: 0 auto;
  left: 50%;
  transform: translateX(-50%);
}

.pencil-input-holder .pencil-svg {
  background: url("../images/pencil.svg") center center no-repeat;
  width: 27px;
  height: 39px;
  display: inline-block;
  position: relative;
  top: 60px;
  left: 20px;
}

input.pencil-input {
  position: relative;
  font-family: 'GT America Compressed Regular';
  text-align: center;
  font-size: 59px;
  color: rgba(255, 255, 255, 0.5);
  background: transparent;
  left: 50%;
  transform: translateX(-50%);
  border: none;
}

input.pencil-input:focus {
  outline: none;
}
<div class="left-side">
  <div class="element-container">
    <div class="element" style="position: relative;">
      Sky
    </div>
    <div class="pencil-input-holder">
      <div class="pencil-svg">
        Pencil
      </div>

      <input class="pencil-input" onChange={this.handleChange} value={this.state.title} />
    </div>
  </div>
</div>
like image 58
Brett DeWoody Avatar answered Oct 09 '22 12:10

Brett DeWoody


I recommend wrapping them and applying flex.

 <div style={{divstyle}}>
   <component1/>
   <component2/> 
 </div>

divstyle = {
  display:'flex',
  justify-content:'center',
  align-items:'center',
} 
like image 42
xSkrappy Avatar answered Oct 09 '22 12:10

xSkrappy