อะไรคือวิธีที่สะอาดที่สุดในการปิดใช้งานเอฟเฟกต์การเปลี่ยน CSS ชั่วคราว


209

ฉันใช้องค์ประกอบ DOM พร้อมเอฟเฟกต์ต่อไปนี้บางส่วน / ทั้งหมด:

#elem {
  -webkit-transition: height 0.4s ease;
  -moz-transition: height 0.4s ease;
  -o-transition: height 0.4s ease;
  transition: height 0.4s ease;
}

ฉันกำลังเขียนปลั๊กอิน jQuery ที่ปรับขนาดองค์ประกอบนี้ฉันต้องปิดใช้งานเอฟเฟกต์เหล่านี้ชั่วคราวเพื่อให้ฉันสามารถปรับขนาดได้อย่างราบรื่น

อะไรคือวิธีปิดการใช้งานเอฟเฟกต์เหล่านี้ที่สวยงามที่สุดชั่วคราว (จากนั้นเปิดใช้งานอีกครั้ง) เนื่องจากอาจถูกนำไปใช้จากผู้ปกครองหรืออาจไม่ได้ใช้เลย


1
ลักษณะนี้มีแนวโน้ม: ricostacruz.com/jquery.transit มันเป็นลิขสิทธิ์ของ MIT ดังนั้นคุณสามารถรวมมันหรือศึกษามันเพื่อดูว่าเขาทำได้อย่างไร
Robert Harvey

คำตอบทั้งหมดเพิ่ม.notransitionระดับ มันจะสมเหตุสมผลมากกว่าที่จะทำในทางอื่นเช่นกำหนดเป้าหมาย#elem.yestransitionด้วย CSS ของคุณและลบคลาสนี้ ที่เอามีน่ารังเกียจ*ใน CSS ของคุณ
marcellothearcane

คำตอบ:


484

คำตอบสั้น ๆ

ใช้ CSS นี้:

.notransition {
  -webkit-transition: none !important;
  -moz-transition: none !important;
  -o-transition: none !important;
  transition: none !important;
}

รวมทั้ง JS นี้ (ไม่มี jQuery) ...

someElement.classList.add('notransition'); // Disable transitions
doWhateverCssChangesYouWant(someElement);
someElement.offsetHeight; // Trigger a reflow, flushing the CSS changes
someElement.classList.remove('notransition'); // Re-enable transitions

หรือ JS นี้ด้วย jQuery ...

$someElement.addClass('notransition'); // Disable transitions
doWhateverCssChangesYouWant($someElement);
$someElement[0].offsetHeight; // Trigger a reflow, flushing the CSS changes
$someElement.removeClass('notransition'); // Re-enable transitions

... หรือรหัสเทียบเท่าโดยใช้ไลบรารีหรือกรอบงานอื่นที่คุณกำลังทำงานด้วย

คำอธิบาย

นี่เป็นปัญหาที่ค่อนข้างบอบบาง

ขึ้นเป็นครั้งแรกคุณอาจต้องการที่จะสร้าง 'notransition' class ที่คุณสามารถนำไปใช้กับองค์ประกอบในการตั้งค่าของพวกเขา*-transitionคุณลักษณะ CSS noneเพื่อ ตัวอย่างเช่น

.notransition {
  -webkit-transition: none !important;
  -moz-transition: none !important;
  -o-transition: none !important;
  transition: none !important;
}

(แยกออกจากกัน - โปรดสังเกตว่าไม่มี-ms-transitionในนั้นคุณไม่จำเป็นต้องใช้ Internet Explorer รุ่นแรกเพื่อรองรับการเปลี่ยนเลยคือ IE 10 ซึ่งรองรับพวกเขาไม่ได้เตรียมการไว้ล่วงหน้า)

แต่นั่นเป็นเพียงรูปแบบและเป็นบิตง่าย เมื่อคุณลองและใช้คลาสนี้คุณจะพบกับดัก กับดักคือรหัสเช่นนี้จะไม่ทำงานอย่างที่คุณคาดหวัง:

// Don't do things this way! It doesn't work!
someElement.classList.add('notransition')
someElement.style.height = '50px' // just an example; could be any CSS change
someElement.classList.remove('notransition')

อย่างไร้เดียงสาคุณอาจคิดว่าการเปลี่ยนแปลงความสูงจะไม่เคลื่อนไหวเพราะมันเกิดขึ้นในขณะที่มีการใช้คลาส 'notransition' ในความเป็นจริงแม้ว่ามันจะเป็นภาพเคลื่อนไหวอย่างน้อยในเบราว์เซอร์ที่ทันสมัยทั้งหมดที่ฉันได้ลอง ปัญหาคือเบราว์เซอร์กำลังแคชการเปลี่ยนแปลงในสไตล์ที่จำเป็นต้องใช้จนกว่า JavaScript จะเสร็จสิ้นการเรียกใช้งานจากนั้นทำการเปลี่ยนแปลงทั้งหมดในการ reflow ครั้งเดียว เป็นผลให้มันทำการ reflow ที่ไม่มีการเปลี่ยนแปลงสุทธิว่าเปิดใช้งานการเปลี่ยนหรือไม่ แต่มีการเปลี่ยนแปลงสุทธิกับความสูง ดังนั้นมันจะเคลื่อนไหวการเปลี่ยนแปลงความสูง

คุณอาจคิดว่าวิธีที่สมเหตุสมผลและสะอาดตาในการหลีกเลี่ยงสิ่งนี้คือการลบการกำจัด 'notransition' ในเวลา 1 มิลลิวินาทีเช่นนี้

// Don't do things this way! It STILL doesn't work!
someElement.classList.add('notransition')
someElement.style.height = '50px' // just an example; could be any CSS change
setTimeout(function () {someElement.classList.remove('notransition')}, 1);

แต่มันก็ไม่ได้ผลเหมือนกัน ฉันไม่สามารถทำลายโค้ดข้างต้นในเบราว์เซอร์ WebKit ได้ แต่ใน Firefox (ทั้งบนเครื่องที่ช้าและเร็ว) บางครั้งคุณจะ (ดูเหมือนจะสุ่ม) จะมีพฤติกรรมเหมือนกับการใช้วิธีการที่ไร้เดียงสา ฉันเดาว่านี่คือสาเหตุที่เป็นไปได้ที่การเรียกใช้ JavaScript จะช้าพอที่ฟังก์ชันการหมดเวลาจะรอดำเนินการตามเวลาที่เบราว์เซอร์ไม่ได้ทำงานและจะคิดเกี่ยวกับการทำ reflow แบบฉวยโอกาสและหากเกิดเหตุการณ์ขึ้น Firefox ดำเนินการฟังก์ชันที่อยู่ในคิวก่อนที่จะทำการ reflow

ทางออกเดียวที่ฉันพบปัญหาคือการบังคับให้ reflow ขององค์ประกอบล้างการเปลี่ยนแปลง CSS ที่ทำกับมันก่อนที่จะลบชั้น 'notransition' มีหลายวิธีในการทำเช่นนี้ - ดูที่นี่สำหรับบางคน สิ่งที่ใกล้เคียงที่สุดคือวิธี 'มาตรฐาน' ในการทำเช่นนี้คือการอ่านoffsetHeightคุณสมบัติขององค์ประกอบ

ทางออกหนึ่งที่ใช้งานได้จริงคือ

someElement.classList.add('notransition'); // Disable transitions
doWhateverCssChangesYouWant(someElement);
someElement.offsetHeight; // Trigger a reflow, flushing the CSS changes
someElement.classList.remove('notransition'); // Re-enable transitions

นี่เป็นซอ JS ที่แสดงให้เห็นถึงสามวิธีที่เป็นไปได้ที่ผมได้อธิบายไว้ที่นี่ (ทั้งวิธีการที่ประสบความสำเร็จหนึ่งและสองคนไม่ประสบความสำเร็จ): http://jsfiddle.net/2uVAA/131/


8
คำตอบที่ยอดเยี่ยม งานที่ดีและชื่นชมตั้งแต่ฉันมาด้วยปัญหาเดียวกัน จะเกิดอะไรขึ้นถ้าฉันต้องการลบการเปลี่ยนประเภทเดียว?
rafaelmorais

2
โซลูชันของคุณถูกต้อง แต่สำหรับผู้ที่มองหาข้อมูลพื้นหลังเพิ่มเติม: stackoverflow.com/a/31862081/1026
Nickolay

2
ไมเนอร์เล็ก ๆ น้อย ๆ กัน IE10 เป็นครั้งแรกที่มีเสถียรภาพรุ่นของ IE ไปยังเรือที่มีการเปลี่ยน unprefixed รุ่นก่อนวางจำหน่ายซึ่งไม่รวม Preview Release ต้องใช้คำนำหน้า -ms- สำหรับการเปลี่ยนพร้อมด้วยสิ่งอื่น ๆ นั่นฉันสงสัยว่าเป็นหนึ่งในเหตุผลที่คำนำหน้า -ms- ปรากฏขึ้นในวันนี้ แน่นอนว่าเหตุผลก็คือลัทธิขนส่งสินค้าทั่วไปที่เราทุกคนรู้จักและชื่นชอบเกี่ยวกับคำนำหน้าของผู้ขาย
BoltClock

1
น่าสนใจที่เพียงแค่ตรวจสอบความสูงชดเชยขององค์ประกอบทริกเกอร์ reflow หวังว่าฉันจะรู้เรื่องนี้เมื่อหนึ่งปีก่อนตอนที่ฉันต่อสู้กับกำแพงด้วยปัญหาเดียวกันนี้ นี่ยังถือว่าเป็นวิธีที่เหมาะสมที่สุดในการจัดการกับสิ่งนี้หรือไม่?
Brett84c

2
เคล็ดลับ reflow ดูเหมือนจะไม่ทำงานเมื่อสร้างภาพเคลื่อนไหวองค์ประกอบ SVG ซึ่งไม่มีแอตทริบิวต์ offsetHeight setTimout ใช้งานได้
piotr_cz

19

ฉันจะสนับสนุนการปิดใช้งานภาพเคลื่อนไหวตามที่ DaneSoul แนะนำ แต่ทำให้การสลับเป็นไปได้ทั่วโลก:

/*kill the transitions on any descendant elements of .notransition*/
.notransition * { 
  -webkit-transition: none !important; 
  -moz-transition: none !important; 
  -o-transition: none !important; 
  -ms-transition: none !important; 
  transition: none !important; 
} 

.notransitionสามารถนำไปใช้กับbodyองค์ประกอบได้อย่างมีประสิทธิภาพเอาชนะภาพเคลื่อนไหวการเปลี่ยนแปลงใด ๆ บนหน้า:

$('body').toggleClass('notransition');

2
จริงๆแล้วนี่เป็นตัวเลือกที่สมบูรณ์แบบที่สุด โดยเฉพาะ * ช่วยได้มากตรวจสอบให้แน่ใจว่าไม่มีภาพเคลื่อนไหวย่อยเรียก ขอบคุณ upvoted
SchizoDuckie

นี่คือคำตอบที่ถูกต้องสำหรับสถานการณ์ที่คุณต้องการทำทั้งหมดในครั้งเดียว ตัวอย่างเช่นฉันต้องการปิดการใช้งานการเปลี่ยนภาพในขณะที่หมุนบนมือถือและนี่ก็เหมาะสำหรับสิ่งนั้น
Ben Lachman

ฉันลงเอยด้วยการใช้สิ่งนี้ใน angularjs ในสถานการณ์ที่ค่อนข้างซับซ้อน แต่โดยพระเจ้าสิ่งนี้มีประโยชน์มากหลังจากการต่อสู้กับหัวหลายวัน
Aditya MP

2
ประสิทธิภาพการทำงานที่ชาญฉลาดฉันไม่สามารถคาดหวังได้ว่านี่จะเป็นความคิดที่ดีเลย "โอ้เพียงแค่ใช้สิ่งนี้กับทุกสิ่งบนหน้าซึ่งจะทำให้สิ่งต่าง ๆ ง่ายขึ้น!"
Lodewijk

1
ควรเลือกทั้ง ".notransition" และ ".notransition *" เพื่อให้ได้ผลอย่างเต็มที่
นาธาน

19

เพิ่มคลาส CSS เพิ่มเติมที่บล็อกช่วงการเปลี่ยนภาพแล้วลบออกเพื่อกลับสู่สถานะก่อนหน้า สิ่งนี้ทำให้ทั้งโค้ด CSS และ JQuery สั้นง่ายและเข้าใจได้ง่าย

CSS :

.notransition {
  -webkit-transition: none !important;
  -moz-transition: none !important;
  -o-transition: none !important;
  -ms-transition: none !important;
  transition: none !important;
}

!important ถูกเพิ่มเข้ามาเพื่อให้แน่ใจว่ากฎนี้จะมี "น้ำหนัก" มากขึ้นเพราะปกติ ID จะเฉพาะเจาะจงกว่าคลาส

JQuery :

$('#elem').addClass('notransition'); // to remove transition
$('#elem').removeClass('notransition'); // to return to previouse transition

5
-1 เพราะมันไม่เพียงพอที่จะแก้ปัญหาสำหรับฉันใน Chrome หรือ Firefox - ถ้าฉันมี Javascript ที่เพิ่มคลาสทำการเปลี่ยนแปลงและลบคลาสออกบางครั้งการเปลี่ยนแปลงก็ยังคงอยู่ ฉันใช้เวลาหนึ่งหรือสองชั่วโมงในการศึกษาปัญหานี้ในรายละเอียดและจะโพสต์คำตอบในภายหลังด้วยปริศนาแสดงกรณีที่วิธีการไร้เดียงสาล้มเหลวรวมทั้งแฮ็คที่เรียบร้อยซึ่งแก้ไขปัญหาที่นี่โดยบังคับให้ reflow ระหว่างการเปลี่ยนแปลงและลบ ชั้นเรียน 'notransition'
Mark Amery

9

สำหรับการแก้ปัญหา JS บริสุทธิ์ (ไม่มีคลาส CSS) เพียงแค่ตั้งค่าไปtransition 'none'หากต้องการคืนค่าการเปลี่ยนแปลงตามที่ระบุใน CSS ให้ตั้งค่าtransitionเป็นสตริงว่าง

// Remove the transition
elem.style.transition = 'none';

// Restore the transition
elem.style.transition = '';

หากคุณใช้คำนำหน้าผู้ขายคุณจะต้องตั้งค่าเหล่านั้นด้วย

elem.style.webkitTransition = 'none'

8

คุณสามารถปิดใช้งานภาพเคลื่อนไหวการเปลี่ยนแปลงและการเปลี่ยนแปลงสำหรับองค์ประกอบทั้งหมดในหน้าด้วยรหัส css นี้

var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '* {' +
'/*CSS transitions*/' +
' -o-transition-property: none !important;' +
' -moz-transition-property: none !important;' +
' -ms-transition-property: none !important;' +
' -webkit-transition-property: none !important;' +
'  transition-property: none !important;' +
'/*CSS transforms*/' +
'  -o-transform: none !important;' +
' -moz-transform: none !important;' +
'   -ms-transform: none !important;' +
'  -webkit-transform: none !important;' +
'   transform: none !important;' +
'  /*CSS animations*/' +
'   -webkit-animation: none !important;' +
'   -moz-animation: none !important;' +
'   -o-animation: none !important;' +
'   -ms-animation: none !important;' +
'   animation: none !important;}';
   document.getElementsByTagName('head')[0].appendChild(style);

1
ประการแรกมันยอดเยี่ยมมากขอบคุณ! ประการที่สองยังมีคุณสมบัติอื่น ๆ ที่ควรจะตั้งค่า; ดูgithub.com/japgolly/test-state/blob/master/util/shared/src/test/…
Golly

@Golly คุณสมบัติอื่น ๆ เหล่านั้นอาจส่งผลต่อการออกแบบขั้นสุดท้าย
jonperl

0

ฉันคิดว่าคุณสามารถสร้างคลาส CSS แยกต่างหากที่คุณสามารถใช้ในกรณีเหล่านี้:

.disable-transition {
  -webkit-transition: none;
  -moz-transition: none;
  -o-transition: color 0 ease-in;
  -ms-transition: none;
  transition: none;
}

จากนั้นใน jQuery คุณจะสลับชั้นเช่นนั้น:

$('#<your-element>').addClass('disable-transition');

ใช่ฉันคิดว่านี่เป็นวิธีที่ดีที่สุดอันที่จริงปลั๊กอินสามารถแทรกบล็อก css นั้นลงในหน้าเว็บได้
Sam Saffron

3
คุณแน่ใจหรือไม่! ผู้ปกครอง CLASS สำคัญจะแทนที่ ID หนึ่ง
DaneSoul

0

หากคุณต้องการโซลูชัน no-jquery ที่ง่ายเพื่อป้องกันการเปลี่ยนแปลงทั้งหมด:

  1. เพิ่ม CSS นี้:
body.no-transition * {
  transition: none !important;
}
  1. แล้วใน js ของคุณ:
document.body.classList.add("no-transition");

// do your work, and then either immediately remove the class:

document.body.classList.remove("no-transition");

// or, if browser rendering takes longer and you need to wait until a paint or two:

setTimeout(() => document.body.classList.remove("no-transition"), 1);

// (try changing 1 to a larger value if the transition is still applying)

-1

หากคุณต้องการลบการเปลี่ยน CSS, การแปลงและภาพเคลื่อนไหวจากหน้าเว็บปัจจุบันคุณสามารถรันสคริปต์เล็ก ๆ น้อย ๆ ที่ฉันเขียน (ภายในคอนโซลเบราว์เซอร์ของคุณ):

let filePath = "https://dl.dropboxusercontent.com/s/ep1nzckmvgjq7jr/remove_transitions_from_page.css";
let html = `<link rel="stylesheet" type="text/css" href="${filePath}">`;
document.querySelector("html > head").insertAdjacentHTML("beforeend", html);

มันใช้ vanillaJS เพื่อโหลดไฟล์ cssนี้ นี่เป็น github repo ในกรณีที่คุณต้องการใช้ในบริบทของ scraper (Ruby-Selenium): remove-CSS-animations-repo


-3

ทำ

$('#elem').css('-webkit-transition','none !important'); 

ใน js ของคุณฆ่ามันเหรอ?

ทำซ้ำอย่างเห็นได้ชัดสำหรับแต่ละ


1
จากนั้นคุณต้องรีเซ็ตหลังจากข้อเท็จจริงดังนั้นคุณต้องเก็บมันไว้ซึ่งจะนำไปสู่จานหม้อไอน้ำในปริมาณที่พอใช้
Sam Saffron

-4

ฉันจะมีคลาสใน CSS ของคุณเช่นนี้:

.no-transition { 
  -webkit-transition: none;
  -moz-transition: none;
  -o-transition: none;
  -ms-transition: none;
  transition: none;
}

แล้วใน jQuery ของคุณ:

$('#elem').addClass('no-transition'); //will disable it
$('#elem').removeClass('no-transition'); //will enable it

1
คุณแน่ใจหรือไม่! ผู้ปกครอง CLASS สำคัญจะแทนที่ ID หนึ่ง
DaneSoul

1
ใช่มันจะเป็นเพราะตอนนี้คุณกำลังกำหนดเป้าหมาย # elem.no-transition ซึ่งเฉพาะเจาะจงมากกว่ารหัส
Moin Zaman

3
@MoinZaman เอ่อ แต่คุณยังไม่ได้กำหนดเป้าหมาย#elem.no-transitionใน CSS .no-transitionของคุณคุณได้กำหนดเป้าหมายเพียง บางทีคุณตั้งใจจะเขียน#elem.no-transitionใน CSS ของคุณ?
Mark Amery
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.