CSS :active 和 :not psuedo 的组合 类
CSS combination of :active and :not psuedo classes
我有一个代码,其中“卡片”class 在单击时将用户带到一篇文章。
其子项“类别”在单击时将用户带到另一个网站。
<div class="card">
<div class="img"></div>
<div class="category"></div>
<div class="title"></div>
<div class="description"></div>
</div>
我正在尝试用 div:active 为这两个 div 编写 CSS 动画。
所以当我有以下内容时,整张卡片都会动画:
.card:active {
transform: translateX(50px);
transition: all 0.5s ease;
}
但我不希望卡片在用户单击 类别 div 时显示动画。
所以,我尝试了类似下面的方法和其他方法,但都没有用。
:not(.category).card:active{
transform: translateX(50px);
transition: all 0.5s ease;
}
是否有 :not 和 :active pseudo classes 的组合,我可以使用它来使 card 在单击时具有动画效果,但是 当 类别 被点击时不 动画?
解决方案 1,仅 CSS
一般可以用...
/* CSS */
.card { pointer-events: none }
.card>:not(.category) { pointer-events: auto } /* all kids except .category */
.card:active { transform: translateX(50px) }
/* HTML */
<div class="card">
<div class="img">image</div>
<div class="category">CATEGORY</div>
<div class="title">no-card</div>
<div class="description">description</div>
</div>
...并点击 .card
的任何子项,除了 class .category
,将触发卡片 :active
事件以及 :hover
。但是,任何未被子元素占用的卡片 space 将 不会触发任何事件 (即 .card:padding
和 .category
不会触发 :active
或 :hover
).
另一个缺点是 .category
根本不会监听任何事件,因此不能成为需要处理这些事件的输入元素(如 <button>
,如演示中所示)。
如果这是可以接受的,则此解决方案最容易编码和维护。
方案二,CSS加JS
此解决方案仅使用简单的 CSS...
.effect:active { transform: translateX(50px) } /* NOT .card:active */
...和一些 Vanilla Javascript(伪代码),在适当的时候简单地 removes/adds 来自 .card
的 .effect
class。
forEach cardList.item do
card.onmouseover = enableEffect();
card.category.onmouseenter = disableEffect();
card.category.onmouseout = enableEffect();
disableEffect = remove class 'effect' from .card
enableEffect = add class 'effect' to .card
下面的代码片段包括这两种解决方案,有大量评论并包括一些额外的响应能力(例如 CSS 列、主要字体和页面间距。使用的数学 MathIsFun: Linear Equation)。
只需复制代码,尽情享受吧!
片段
'use-strict';
// Traverse an array and execute the passed callback function for each array element found
var forEachEntryIn = function (array, callback, scope) {
for (var i = 0; i < array.length; i++) { callback.call(scope, i, array[i]); } };
// Get the list of cards
var cards = document.getElementsByClassName('card');
// Make this a function and you can toggle it with a <button>
var DEBUG = false; // set to 'true' for debug view and some console output
(DEBUG) ? document.body.setAttribute('outlines','1') : document.body.setAttribute('outlines','0');
// Traverse the list of cards
forEachEntryIn( cards,
function (idx,card,scope) {
// '.effect' is needed by default,
// so why add it in HTML class="" property when we can do it here...
card.classList.add('effect'); // remove if you want to assign in HMTL anyway
/*
MOUSEOVER events are bubbled to child elements
MOUSEENTER does not bubble, needed on '.category'
target: the element that triggered the event ('.card' OR any of its child elements)
currentTarget: the element that the event listener is attached to: '.card'
*/
card.onmouseover = function(e) { // Attach 'MOUSEOVER' listener to '.card'
// Parent check: event may be bubbled (from any '.card' children)
// So, is the parent a '.card' or maybe its parent?
if (e.target.parentElement == e.currentTarget) {
enableEffect(e.target.parentElement); // Activate '.card' animation
};
// NOTE: Disable the check, click a card and see what happens....funny!
};
var category = card.querySelector('.category');
if (card.contains(category)) {
category.onmouseenter = function(e) { disableEffect(e.currentTarget.parentElement); };
category.onmouseout = function(e) { enableEffect (e.currentTarget.parentElement); };
};
} // end function (idx,el,scope)
); // end forEachEntryIn
// Helper functions to keep main loop readable
function enableEffect(parent) {
if (!parent.classList.contains('effect')) { // if parent has no '.effect'
parent.classList.add('effect'); // then add it
};
if (DEBUG) logInfo(parent);
};
function disableEffect(parent) {
if (parent.classList.contains('effect')) { // parent if has '.effect'
parent.classList.remove('effect'); // then remove it
};
if (DEBUG) logInfo(parent);
};
// For debugging
function logInfo(p) {
console.log( // Show some info in browser console
((p.className) ? '<' + p.tagName +' class="' + p.className + '">': '<' + p.tagName +'>' ),
p.classList.contains('effect')
);
};
/********************************/
/* demo for CSS only solution 1 */
/********************************/
.no-card {
pointer-events: none;
}
.no-card>:not(.category) {
pointer-events: auto;
}
.no-card:active {
transform: translateX(50px);
transition: all 0.5s ease;
}
/***********************************/
/* demo for CSS plus JS solution 2 */
/***********************************/
/* class will be assigned with JS */
.effect:active {
transform: translateX(50px);
transition: all 0.5s ease;
}
/*****************************************************/
/* below just demo, everything can be safely removed */
/*****************************************************/
/**************************/
/* preferred global rules */
/**************************/
html,body { box-sizing: border-box; width: 100%; max-width: 100% }
*::before,*::after, * { box-sizing: inherit }
body { margin: 0 }
/* ALL math reference: https://www.mathsisfun.com/equation_of_line.html */
/* responsive base font size using y = mx + b */
html { font-size: calc(0.625vmin + 0.75rem) } /* (320,14)(1280,20) */
/* prohibit user from selecting text (put in <body>) */
[no-select] { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none }
[do-select] { -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text; cursor: auto }
/* enable user to select text (put in specific elements) */
/* to show all elements with outlines (assigned to <body> with JS) */
[outlines="1"] * { outline: 1px dashed }
/***********************************/
/* Extra: plain responsive columns */
/***********************************/
body {
/*
responsive page padding using y = mx + b
p1(320,32) p2(1920, 72) => y = 0.025x + 24
p3(320, 8) p4(1920,320) => y = 0.195x - 54.4
*/
padding: calc(2.5vh + 24px) calc(19.5vw - 54.4px);
}
.cardList {
column-count: 3; /* preferred number of columns given column-width */
column-gap: 0; /* handled with card margins */
/*
column width using y = mx + b
mobile/tablet, 1 column : 320 - 60 = 260px
desktop, 3 columns: (1920 - 640) / 3 = 426 minus animation gap = 376px
p1(320,260) p2(1920,376)
=> y = 7.25x + 236.8
*/
column-width: calc(7.25vw + 230.8px); /* (320,260)(1920,376) */
/* (320,260)(1920,376) for scrollbar => 236.8 - (18/3) = 230.8px */
}
.card {
break-inside: avoid; /* don't split card over columns */
}
/******************/
/* card eye-candy */
/******************/
.wrapper,
.cardList {
background-color: rgba(0,0,0,.1); /* just to review body padding */
padding: 2rem 0;
}
.no-card, .card {
background-color: CornSilk;
padding: 1rem;
margin : 1rem;
margin-right: 60px; /* animation width plus 10px space */
/* GMC elevation 1dp */
box-shadow: 0px 2px 1px -1px rgba(0,0,0,.20),
0px 1px 1px 0px rgba(0,0,0,.14),
0px 1px 3px 0px rgba(0,0,0,.12);
}
.card:first-child { margin-top: 0 } /* otherwise jagged column tops */
/* Some :hover animation */
.no-card:hover, .card:hover {
/* GMC elevation 3dp */
box-shadow: 0px 3px 3px -2px rgba(0,0,0,.20),
0px 3px 4px 0px rgba(0,0,0,.14),
0px 1px 8px 0px rgba(0,0,0,.12);
}
<body no-select>
<h2>solution 1, CSS only</h2>
<div class="wrapper">
<div class="no-card">
<div class="img">image</div>
<button class="category">CATEGORY</button>
<div class="title">no-card</div>
<div class="description">description</div>
</div>
</div>
<h2>solution 2, CSS plus JS</h2>
<div class="cardList">
<div class="card">
<div class="img">image</div>
<button class="category">CATEGORY</button>
<div class="title">card 1</div>
<div class="description">description</div>
</div>
<div class="card">
<div class="img">image</div>
<button class="category">CATEGORY</button>
<div class="title">card 2</div>
<div class="description">description</div>
</div>
<div class="card">
<div class="img">image</div>
<button class="category">CATEGORY</button>
<div class="title">card 3</div>
<div class="description">description</div>
</div>
<div class="card">
<div class="img">image</div>
<button class="category">CATEGORY</button>
<div class="title">card 4</div>
<div class="description">description</div>
</div>
<div class="card">
<div class="img">image</div>
<div>some other element</div>
<div class="title">card 5</div>
<div class="description">description</div>
</div>
<div class="card">
<div class="img">image</div>
<button class="category">CATEGORY</button>
<div class="title">card 6</div>
<div class="description">description</div>
</div>
</div>
</body>
我有一个代码,其中“卡片”class 在单击时将用户带到一篇文章。 其子项“类别”在单击时将用户带到另一个网站。
<div class="card">
<div class="img"></div>
<div class="category"></div>
<div class="title"></div>
<div class="description"></div>
</div>
我正在尝试用 div:active 为这两个 div 编写 CSS 动画。 所以当我有以下内容时,整张卡片都会动画:
.card:active {
transform: translateX(50px);
transition: all 0.5s ease;
}
但我不希望卡片在用户单击 类别 div 时显示动画。 所以,我尝试了类似下面的方法和其他方法,但都没有用。
:not(.category).card:active{
transform: translateX(50px);
transition: all 0.5s ease;
}
是否有 :not 和 :active pseudo classes 的组合,我可以使用它来使 card 在单击时具有动画效果,但是 当 类别 被点击时不 动画?
解决方案 1,仅 CSS
一般可以用...
/* CSS */
.card { pointer-events: none }
.card>:not(.category) { pointer-events: auto } /* all kids except .category */
.card:active { transform: translateX(50px) }
/* HTML */
<div class="card">
<div class="img">image</div>
<div class="category">CATEGORY</div>
<div class="title">no-card</div>
<div class="description">description</div>
</div>
...并点击 .card
的任何子项,除了 class .category
,将触发卡片 :active
事件以及 :hover
。但是,任何未被子元素占用的卡片 space 将 不会触发任何事件 (即 .card:padding
和 .category
不会触发 :active
或 :hover
).
另一个缺点是 .category
根本不会监听任何事件,因此不能成为需要处理这些事件的输入元素(如 <button>
,如演示中所示)。
如果这是可以接受的,则此解决方案最容易编码和维护。
方案二,CSS加JS
此解决方案仅使用简单的 CSS...
.effect:active { transform: translateX(50px) } /* NOT .card:active */
...和一些 Vanilla Javascript(伪代码),在适当的时候简单地 removes/adds 来自 .card
的 .effect
class。
forEach cardList.item do
card.onmouseover = enableEffect();
card.category.onmouseenter = disableEffect();
card.category.onmouseout = enableEffect();
disableEffect = remove class 'effect' from .card
enableEffect = add class 'effect' to .card
下面的代码片段包括这两种解决方案,有大量评论并包括一些额外的响应能力(例如 CSS 列、主要字体和页面间距。使用的数学 MathIsFun: Linear Equation)。
只需复制代码,尽情享受吧!
片段
'use-strict';
// Traverse an array and execute the passed callback function for each array element found
var forEachEntryIn = function (array, callback, scope) {
for (var i = 0; i < array.length; i++) { callback.call(scope, i, array[i]); } };
// Get the list of cards
var cards = document.getElementsByClassName('card');
// Make this a function and you can toggle it with a <button>
var DEBUG = false; // set to 'true' for debug view and some console output
(DEBUG) ? document.body.setAttribute('outlines','1') : document.body.setAttribute('outlines','0');
// Traverse the list of cards
forEachEntryIn( cards,
function (idx,card,scope) {
// '.effect' is needed by default,
// so why add it in HTML class="" property when we can do it here...
card.classList.add('effect'); // remove if you want to assign in HMTL anyway
/*
MOUSEOVER events are bubbled to child elements
MOUSEENTER does not bubble, needed on '.category'
target: the element that triggered the event ('.card' OR any of its child elements)
currentTarget: the element that the event listener is attached to: '.card'
*/
card.onmouseover = function(e) { // Attach 'MOUSEOVER' listener to '.card'
// Parent check: event may be bubbled (from any '.card' children)
// So, is the parent a '.card' or maybe its parent?
if (e.target.parentElement == e.currentTarget) {
enableEffect(e.target.parentElement); // Activate '.card' animation
};
// NOTE: Disable the check, click a card and see what happens....funny!
};
var category = card.querySelector('.category');
if (card.contains(category)) {
category.onmouseenter = function(e) { disableEffect(e.currentTarget.parentElement); };
category.onmouseout = function(e) { enableEffect (e.currentTarget.parentElement); };
};
} // end function (idx,el,scope)
); // end forEachEntryIn
// Helper functions to keep main loop readable
function enableEffect(parent) {
if (!parent.classList.contains('effect')) { // if parent has no '.effect'
parent.classList.add('effect'); // then add it
};
if (DEBUG) logInfo(parent);
};
function disableEffect(parent) {
if (parent.classList.contains('effect')) { // parent if has '.effect'
parent.classList.remove('effect'); // then remove it
};
if (DEBUG) logInfo(parent);
};
// For debugging
function logInfo(p) {
console.log( // Show some info in browser console
((p.className) ? '<' + p.tagName +' class="' + p.className + '">': '<' + p.tagName +'>' ),
p.classList.contains('effect')
);
};
/********************************/
/* demo for CSS only solution 1 */
/********************************/
.no-card {
pointer-events: none;
}
.no-card>:not(.category) {
pointer-events: auto;
}
.no-card:active {
transform: translateX(50px);
transition: all 0.5s ease;
}
/***********************************/
/* demo for CSS plus JS solution 2 */
/***********************************/
/* class will be assigned with JS */
.effect:active {
transform: translateX(50px);
transition: all 0.5s ease;
}
/*****************************************************/
/* below just demo, everything can be safely removed */
/*****************************************************/
/**************************/
/* preferred global rules */
/**************************/
html,body { box-sizing: border-box; width: 100%; max-width: 100% }
*::before,*::after, * { box-sizing: inherit }
body { margin: 0 }
/* ALL math reference: https://www.mathsisfun.com/equation_of_line.html */
/* responsive base font size using y = mx + b */
html { font-size: calc(0.625vmin + 0.75rem) } /* (320,14)(1280,20) */
/* prohibit user from selecting text (put in <body>) */
[no-select] { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none }
[do-select] { -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text; cursor: auto }
/* enable user to select text (put in specific elements) */
/* to show all elements with outlines (assigned to <body> with JS) */
[outlines="1"] * { outline: 1px dashed }
/***********************************/
/* Extra: plain responsive columns */
/***********************************/
body {
/*
responsive page padding using y = mx + b
p1(320,32) p2(1920, 72) => y = 0.025x + 24
p3(320, 8) p4(1920,320) => y = 0.195x - 54.4
*/
padding: calc(2.5vh + 24px) calc(19.5vw - 54.4px);
}
.cardList {
column-count: 3; /* preferred number of columns given column-width */
column-gap: 0; /* handled with card margins */
/*
column width using y = mx + b
mobile/tablet, 1 column : 320 - 60 = 260px
desktop, 3 columns: (1920 - 640) / 3 = 426 minus animation gap = 376px
p1(320,260) p2(1920,376)
=> y = 7.25x + 236.8
*/
column-width: calc(7.25vw + 230.8px); /* (320,260)(1920,376) */
/* (320,260)(1920,376) for scrollbar => 236.8 - (18/3) = 230.8px */
}
.card {
break-inside: avoid; /* don't split card over columns */
}
/******************/
/* card eye-candy */
/******************/
.wrapper,
.cardList {
background-color: rgba(0,0,0,.1); /* just to review body padding */
padding: 2rem 0;
}
.no-card, .card {
background-color: CornSilk;
padding: 1rem;
margin : 1rem;
margin-right: 60px; /* animation width plus 10px space */
/* GMC elevation 1dp */
box-shadow: 0px 2px 1px -1px rgba(0,0,0,.20),
0px 1px 1px 0px rgba(0,0,0,.14),
0px 1px 3px 0px rgba(0,0,0,.12);
}
.card:first-child { margin-top: 0 } /* otherwise jagged column tops */
/* Some :hover animation */
.no-card:hover, .card:hover {
/* GMC elevation 3dp */
box-shadow: 0px 3px 3px -2px rgba(0,0,0,.20),
0px 3px 4px 0px rgba(0,0,0,.14),
0px 1px 8px 0px rgba(0,0,0,.12);
}
<body no-select>
<h2>solution 1, CSS only</h2>
<div class="wrapper">
<div class="no-card">
<div class="img">image</div>
<button class="category">CATEGORY</button>
<div class="title">no-card</div>
<div class="description">description</div>
</div>
</div>
<h2>solution 2, CSS plus JS</h2>
<div class="cardList">
<div class="card">
<div class="img">image</div>
<button class="category">CATEGORY</button>
<div class="title">card 1</div>
<div class="description">description</div>
</div>
<div class="card">
<div class="img">image</div>
<button class="category">CATEGORY</button>
<div class="title">card 2</div>
<div class="description">description</div>
</div>
<div class="card">
<div class="img">image</div>
<button class="category">CATEGORY</button>
<div class="title">card 3</div>
<div class="description">description</div>
</div>
<div class="card">
<div class="img">image</div>
<button class="category">CATEGORY</button>
<div class="title">card 4</div>
<div class="description">description</div>
</div>
<div class="card">
<div class="img">image</div>
<div>some other element</div>
<div class="title">card 5</div>
<div class="description">description</div>
</div>
<div class="card">
<div class="img">image</div>
<button class="category">CATEGORY</button>
<div class="title">card 6</div>
<div class="description">description</div>
</div>
</div>
</body>