css-переход не работает, если элемент скрыт - PullRequest
0 голосов
/ 24 января 2019

У меня 2 div с, один из них скрыт через display:none;.Оба имеют одинаковый переход CSS для свойства right.

. Если я изменю свойство right через JQuery и покажу скрытое значение div, используя $.css('display','none') или $.show() или $.toggle() и т. д. скрытый div рисует мгновенно в конечной позиции

$('button').on('click',function(){
  $('.b').show();
  $('.b').css('right','80%');
  $('.a').css('right','80%');
})
body {
  width:800px;
  height:800px;
}

div {
  width:50px;
  height:50px;
  background-color:#333;
  position:absolute;
  display:none;
  right:5%;
  top:0;
  transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1);
  color: white;
}

.a {
  display:block;
  top:60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='a'>A
</div>
<div class='b'>B
</div>
<button>Launch</button>

Если я использую $.animate(), это будет работать.Но мой вопрос таков;Это ошибка или нормальное поведение?

Редактировать Не является дубликатом Переходы на дисплее: свойство причина здесь не в том, чтобы анимировать свойство дисплея иливидимость

Ответы [ 5 ]

0 голосов
/ 24 января 2019

Чтобы ясно понять ситуацию, вам нужно понять связь между CSSOM и DOM.

В предыдущем Q / A я немного развил то, как redraw процесс работает.
По сути, есть три шага: манипулирование DOM, перекомпоновка и рисование.

  • Первый ( манипулирование DOM ) просто модифицируетобъект js, и все это синхронно.
  • Второй ( reflow , он же layout ) - это тот, который нас интересует, и он немного сложнее, поскольку нужны только некоторые методы DOM и операция рисованияЭто.Он состоит в обновлении всех правил CSS и пересчете всех вычисленных стилей для каждого элемента на странице.
    Будучи довольно сложной операцией, браузеры будут пытаться делать это как можно реже.
  • Третий ( рисование ) выполняется не более 60 раз в секунду при максимуме (только при необходимости).

Переходы CSS работают путем перехода из одного состояния в другое.И чтобы сделать это, они смотрят на последнее вычисленное значение вашего элемента, чтобы создать начальное состояние.
Поскольку браузеры пересчитывают вычисленные стили только тогда, когда это требуется, в момент начала перехода ни один изприменяемые вами DOM-манипуляции еще эффективны.

Итак, в вашем первом сценарии, когда рассчитывается начальное состояние перехода, у нас есть

.b { computedStyle: {display: none} }

... и все.

Потому что, да, вот насколько мощным является display: none для CSSOM;если элемент имеет display: none, то его не нужно рисовать, он не существует.

Так что я даже не уверен, что алгоритм перехода сработает, но даже если бы он это сделал, начальное состояние было бы недопустимым для любого переходного значения, поскольку все вычисленные значения простоnull.

Ваш элемент .a, видимый с начала, не имеет этой проблемы и может быть перенесен.

И если вы можете заставить его работать с задержкой (вызванной $.animate), это потому, что между DOM-манипулятором ', который действительно изменил свойство display, и выполнением этого отложенного DOM-манипулятора'который запускает переход, браузер запустил reflow (например, из-за того, что сработала v-синхронизация экрана и что операция paint сработала).


Теперь, это не часть вопроса, но, поскольку мы лучше понимаем, что происходит, мы также можем лучше контролировать его .

Действительно, некоторые методы DOM необходимо иметь обновленные расчетные значения.Например, Element.getBoundingClientRect, или element.offsetHeight, или getComputedStyle(element).height и т. Д. Все это требует всей страницы , чтобы обновлять вычисленные значения, чтобы бокс создавался правильно (например, элемент мог иметь толчок поляболее или менее, и т. д.).

Это означает, что нам не нужно быть в неизвестном, когда браузер сработает reflow , мы можем заставить его это сделатькогда мы хотим.

Но помните, все элементы на странице должны быть обновлены, это не маленькая операция, и если браузеры снисходительны сделать это, есть веская причина.

Так что лучше используйте его время от времени, не чаще, чем один раз за кадр.

К счастью, веб-API дали нам возможность перехватить некоторый js-код непосредственно перед выполнением этой операции рисования: requestAnimationFrame .

Так что лучше всего - принудительно выполнить перекомпоновку.только один раз в этом обратном вызове перед рисованием, и для вызова всего, что требует обновленных значений из этого обратного вызова.

$('button').on('click',function(){
  $('.b').show(); // apply display:block synchronously
  
  requestAnimationFrame(() => { // wait just before the next paint
    document.body.offsetHeight; // force a reflow
    // trigger the transitions
    $('.b').css('right','80%');
    $('.a').css('right','80%');
  });
})
body {
  width:800px;
  height:800px;
}

div {
  width:50px;
  height:50px;
  background-color:#333;
  position:absolute;
  display:none;
  right:5%;
  top:0;
  transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1);
  color: white;
}

.a {
  display:block;
  top:60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='a'>A
</div>
<div class='b'>B
</div>
<button>Launch</button>

Но, честно говоря, это не всегда легко настроить, поэтому, если вы уверены, что это то, что будет запускаться спорадически, вы можетебыть ленивым и делать все это синхронно:

$('button').on('click',function(){
  $('.b').show(); // apply display:block
  document.body.offsetHeight; // force a reflow
  // trigger the transitions
  $('.b').css('right','80%');
  $('.a').css('right','80%');
})
body {
  width:800px;
  height:800px;
}

div {
  width:50px;
  height:50px;
  background-color:#333;
  position:absolute;
  display:none;
  right:5%;
  top:0;
  transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1);
  color: white;
}

.a {
  display:block;
  top:60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='a'>A
</div>
<div class='b'>B
</div>
<button>Launch</button>
0 голосов
/ 24 января 2019

Это не ошибка, функция jQuery show() принимает 400ms, чтобы показать элемент, просто используйте show(0)

$('button').on('click',function(){
  $('.b').show(0);
  $('.b').css('right','80%');
  $('.a').css('right','80%');
})
body {
  width:800px;
  height:800px;
}

div {
  width:50px;
  height:50px;
  background-color:#333;
  position:absolute;
  display:none;
  right:5%;
  top:0;
  transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1);
  color: white;
}

.a {
  display:block;
  top:60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='a'>A
</div>
<div class='b'>B
</div>
<button>Launch</button>
0 голосов
/ 24 января 2019

jQuery show() без параметра в основном делает это

$('.b').css('display', 'block');

Итак, что вы делаете, это

$('button').on('click',function(){
  $('.b').css('display', 'block');
  $('.b').css('right','80%');
  $('.a').css('right','80%');
})

, которое в основном совпадает с

$('button').on('click',function(){
  $('.b').css({
    'display': 'block',
    'right': '80%'
  });
  $('.a').css('right','80%');
})

Но вы не можете ничего изменить, если одновременно изменяется отображение.

Добавление значения длительности к вызову show() делает что-то более сложное, чем простоизменение display.Он добавит элемент в очередь анимации следующим образом:

$('.b').css({
  'display': 'block', 
  'overflow': 'hidden',
  'height': '0',
  'width': '0',
  'margin': '0',
  'width': '0',
  'opacity': '0'
});
$('.b').animate({
  height: '50px',
  padding: '0px',
  margin: '0px', 
  width: '50px', 
  opacity: '1'
}, 0)

Итак, вам нужно поместить значение продолжительности 0 (ноль) в вызов show() в качестве параметра

$('button').on('click',function(){
  $('.b').show(0);
  $('.b').css('right','80%');
  $('.a').css('right','80%');
})
body {
  width:800px;
  height:800px;
}

div {
  width:50px;
  height:50px;
  background-color:#333;
  position:absolute;
  display:none;
  right:5%;
  top:0;
  transition:right .5s .1s cubic-bezier(0.645, 0.045, 0.355, 1);
  color: white;
}

.a {
  display:block;
  top:60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='a'>A
</div>
<div class='b'>B
</div>
<button>Launch</button>
0 голосов
/ 24 января 2019

Лично я бы проверил, виден ли элемент после его показа.Затем продолжите через jQuery.

Как это: https://jsfiddle.net/789su6xb/

$('button').on('click',function(){

    var b = $('.b');
    b.show();

    if(b.is(":visible")) {
        $('.b').css('right','80%');
        $('.a').css('right','80%');
    }

});
0 голосов
/ 24 января 2019

Проверьте эту скрипку. Просто нужно добавить тайм-аут

$('button').on('click',function(){
  $('.b').show();
  setTimeout(function(){ $('.b').css('right','80%');
  $('.a').css('right','80%'); }, 0);
  
})
body {
  width:800px;
  height:800px;
}

div {
  width:50px;
  height:50px;
  background-color:#333;
  position:absolute;
  display:none;
  right:5%;
  top:0;
  transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1);
}

.a {
  display:block;
  top:20%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='a'>
</div>
<div class='b'>
</div>
<button>Launch</button>

https://jsfiddle.net/qu2pybch/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...