Generic Nerd
Generic Nerd

Reputation: 327

CSS transform without affecting child elements?

I am trying to have a card element move up on hover and then back down when it is no longer hovered. I am currently achieving this by using transform and translate in CSS. However, I have noticed that this can affect the children elements as well as the element that I want this animation affected by. Here is the HTML and CSS for the card that I have at the moment:

.server :hover {
  -moz-transform: translate(0, -2px);
  -ms-transform: translate(0, -2px);
  -o-transform: translate(0, -2px);
  -webkit-transform: translate(0, -2px);
  transform: translate(0, -2px);
  transition-duration: 0.3s;
  transition-timing-function: ease-in-out;
}
<div class="server">
  <div class="card m-2 p-1 text-center">
    <p>Child element</p>
  </div>
</div>

Upvotes: 0

Views: 4896

Answers (3)

slynagh
slynagh

Reputation: 601

You've used a compound selector when what you probably want is a chain selector. Just add the :hover pseudo selector, without a space, directly to the element you want to affect.

.card {
  /* transitions are needed when hover state ends, so set up rules here */
  transform: translate(0, 0);
  transition-property: transform;
  transition-duration: 0.3s;
  transition-timing-function: ease-in-out;
}
.card:hover { /* note: no space */
  transform: translate(0, -2px);
}
<div class="server">
  <div class="card m-2 p-1 text-center">
    <p>Child element</p>
  </div>
</div>

Upvotes: 1

disinfor
disinfor

Reputation: 11533

Since children elements would always move with their parent element (same applies to opacity), you can set the opposite transform on all children.

I added a red background on the card and set > * all children to have the opposite transform.

.server :hover {
  -moz-transform: translate(0, -2px);
  -ms-transform: translate(0, -2px);
  -o-transform: translate(0, -2px);
  -webkit-transform: translate(0, -2px);
  transform: translate(0, -2px);
  transition-duration: 0.3s;
  transition-timing-function: ease-in-out;
}

.server :hover > * {
  transform: translate(0, 2px);
  transition-duration: 0.3s;
  transition-timing-function: ease-in-out;
}

.card {
  background: red;
}
<div class="server">
  <div class="card m-2 p-1 text-center">
    <p>Child element</p>
  </div>
  
  
  <div class="card m-2 p-1 text-center">
    <p>Child element</p>
    <p>Child element</p>
    <p>Child element</p>
    <p>Child element</p>
    <p>Child element</p>
    <p>Child element</p>
  </div>
  
  
</div>

Since I'm not sure what your card element is actually showing, you could also use a pseudo ::before or ::after and assign the transform to that:

.server :hover::after {
  transform: translate(0, -2px);
  transition-duration: 0.3s;
  transition-timing-function: ease-in-out;
}

.card {
  position: relative;
  z-index: 1;
}

.card::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  background: red;
  width: 100%;
  height: 100%;
  z-index: -1;
}

.card>* {
  z-index: 5;
}
<div class="server">
  <div class="card m-2 p-1 text-center">
    <p>Child element</p>
    <p>Child element</p>
    <p>Child element</p>
    <p>Child element</p>
    <p>Child element</p>
  </div>
</div>

Upvotes: 3

Mech
Mech

Reputation: 4015

You can specify by using :not

.server :hover :not(p) {
  -moz-transform: translate(0, -2px);
  -ms-transform: translate(0, -2px);
  -o-transform: translate(0, -2px);
  -webkit-transform: translate(0, -2px);
  transform: translate(0, -2px);
  transition-duration: 0.3s;
  transition-timing-function: ease-in-out;
}
<div class="server">
  <div class="card m-2 p-1 text-center">
    <p>Child element</p>
    <div>Child element</div>
  </div>
</div>

Upvotes: 2

Related Questions