Обходной путь из-за отсутствия функции CSS для «подавления унаследованных стилей» (и фонов?) - PullRequest
25 голосов
/ 10 ноября 2011

У меня DOM-ситуация выглядит следующим образом:

  • A является предком B , который, в свою очередь, является предком C

  • Изначально A имеет стили, которые наследуются от B и C

  • Я хочу временно выделить B , присвоив ему выделенный класс

    ... однако ...

  • Я хочу "избежать" выделения на C , чтобы она менялась как можно меньше

Кажется, это невозможно в рамках каскадной парадигмы CSS. Единственный способ «отменить» стиль - применить переопределяющий стиль. Моя проблема в том, что выделенный код находится в плагине, который хочет хорошо играть с существующим CSS произвольной страницы ... мои селекторы такие:

/* http://www.maxdesign.com.au/articles/multiple-classes/ */
.highlighted.class1 {
    background-color: ...
    background-image: ...
    ...
}
.highlighted.class2 {
   ...
}
/* ... */
.highlighted.classN {
   ...
}

Фон сложен ... потому что, хотя он не является унаследованным свойством CSS, изменение фона предка может изменить внешний вид потомка (если у него прозрачный фон). Так что это пример чего-то, что вызывает тот вид разрушения, который я пытаюсь отрицать. : - /

Есть ли случаи, когда люди подавляли наследование изменений таким образом? Возможно, использовать такие приемы, как кэширование вычисленных стилей ? Я ищу любой метод по умолчанию, который может быть, по крайней мере, немного умнее, чем ловушка уровня функции, которая говорит: «Эй, плагин выделил этот узел ... делай то, что тебе нужно для визуальной компенсации».


ОБНОВЛЕНИЕ Я создал базовую JsFiddle этого сценария, чтобы сделать обсуждение более понятным:

http://jsfiddle.net/HostileFork/7ku3g/

Ответы [ 9 ]

4 голосов
/ 14 ноября 2011

Если я правильно понимаю, вы хотите вырезать «дыру» на фоне предка.Единственный способ, которым я могу придумать, это использовать <canvas>, чтобы вырезать отверстие, а затем использовать полученное изображение в качестве фона предка.

Вот мой код: http://jsfiddle.net/7ku3g/24/

Iиспользовал логотип JS Fiddle в качестве водяного знака, потому что вы не можете извлечь содержимое холста с привлеченными к нему ресурсами из разных источников.

Обновление: вы также хотели бы прослушать события resize, чтобы обновить фон какразмер окна изменяется.

2 голосов
/ 17 ноября 2011

У меня есть решение, которое помогает с не фоновыми стилями. Вы можете увидеть скрипку http://jsfiddle.net/7ku3g/83/, которая является только грубым понятием. Некоторые ключевые моменты: 1) обязательно, чтобы добавленный элемент styleControl был добавлен к внутреннему самому содержащему элементу. Например, вы добавили класс .highlight к элементу .bClass, но в нем был еще один элемент полной обертки, blockquote. 2) Вы хотите удалить элемент styleControl после удаления класса выделения.

В общем, идея состоит в том, чтобы добавить невидимый элемент стиля сначала во внутреннюю оболочку, а затем использовать общий селектор одноуровневых элементов ~ и :not для стилизации элементов вниз. Опять же, это не решает ваши проблемы с фоном , но, кажется, это способ помочь решить истинные наследуемые свойства, поскольку эти стили НЕ применяются к div-обертке, а к недавно созданному первому брату в группе и свойства, примененные на основе этого родного брата, только к тем, к которым они должны применяться.

Одна из проблем, связанных с этой техникой, - это любой «голый текст» (см. http://jsfiddle.net/7ku3g/84/), тогда он не будет стилизован. Так что это не полное решение вашей проблемы. РЕДАКТИРОВАТЬ: Для таких случаев может сработать захват и добавление тщательно обработанных span вокруг этих обнаженных узлов. Что-то похожее на: Стиль определенного символа в строке .

CSS

.highlight.bClass  {
    background-image: url('http://hostilefork.com/shared/stackoverflow/cc-by-nc-nd.png');
    background-repeat: repeat;
}

.highlight.bClass .styleControl {
    width: 0;
    height: 0;
    position: absolute;
}

.highlight.bClass .styleControl ~ *:not(.cClass) {
    color: red;
}

ОБНОВЛЕНИЕ: Некоторое дальнейшее объяснение, основанное на комментариях HostileFork. Во-первых, мое решение здесь имеет значение только в том случае, если есть дочерний элемент, который вы хотите запретить наследовать стили (фактические наследуемые стили), которые вы добавляете. Во-вторых, может потребоваться добавить несколько, в зависимости от того, насколько глубоко они вложены. Вот несколько псевдокодов html для обсуждения:

<div> (containing licensed material)
    <childA1> (this is the wrapping blockquote in your example; could be anything)
       <scriptAddedStyleElementB0>
       <childB1>content<endchildB1> (apply styles)
       <childB2>content<endchildB2> (don't apply styles)
       <childB3> (don't apply styles because a child is not having styles applied)
          <scriptAddedStyleElementC0>
          <childC1> (apply styles)
            <!-- noScriptAddedStyleElementD0 -->
            <childD1>content<endchildD1>
            <childD2>content<endchildD2>
          <endchildC1> 
          <childC2>content<endchildC2> (don't apply styles)
       <endchildB3>
    <end-childA1>
<end-div1>

Вы нацелены на самый дальний div, чтобы применить класс highlight к определенным детям, которых вы не хотите затрагивать. Обратите внимание, что A1 и B3 сами не содержат никакого контента (текста / изображений), они просто содержат другие элементы. Это «обертки» в моем использовании этого термина (они просто используются для группировки своих детей, хотя у них может быть стиль).

Чтобы ответить на ваш вопрос «когда нужно прекратить погружение», это когда вы достигаете точки, когда вас больше не волнует наследование стилей. В приведенном выше примере необходимо добавить 2 элемента оформления, один в B0 и один в C0, но не в D0. Это связано с тем, что общий селектор брата ~ применяется только к элементам, у которых тот же родительский элемент и которые следуют за этого брата. Таким образом, B0 собирается применить стили к B1, но не к B2 (нелицензионному) или B3 (содержит нелицензионное). Элемент C0 собирается применить стили к C1 (и его лицензированным дочерним элементам D1 и D2), но избегает стилизации C2. Содержимое B2 и C2 будет по-прежнему наследовать исходные стили от div-оболочки (C2 через B3), в то время как B1, C1, D1, D2 получат стиль лицензирования.

Трудности в этом заключаются в том, что: 1) более ранние версии IE (7 и 8) не распознают некоторые из этих css, в частности селектор :not. Это может потенциально обойтись. 2) мои предыдущие заметки о «голом тексте» или контенте. Если бы B3 выглядел так:

 <childB3> 
    <scriptAddedStyleElementC0>
    Some unwrapped text
    <childC1>...<endchildC1>
    Some other unwrapped text and an <img> tag
    <childC2>...<endchildC2>
    More unwrapped text
 <endchildB3>

Если для лицензирования нужно было стилизовать развернутый текст B3 (в вашем примере он стал красным), вам нужно было бы найти все текстовые узлы с помощью javascript и обернуть их в элементы span, чтобы применить стиль, потому что если вы применяете стиль стиль к B3, тогда он унаследует к C2, который вам не нужен.

Нет сомнений, что то, что вы ищете, трудно достичь. Это было бы невозможно с помощью CSS до появления общего селектора, и это может стать проще с обсуждаемыми стандартами CSS4 (для этой ситуации может быть использована возможность стилизовать родительские элементы от дочерних элементов).

2 голосов
/ 14 ноября 2011

Как уже указывало тридцать тридцати, фон не является унаследованным свойством, а просто светит как истина, так как дочерние элементы по умолчанию прозрачны.Так что на самом деле единственный способ заставить их имитировать желаемое поведение - установить для них фон (-image / color), который либо применяется к родительскому элементу (= div#a) элемента подсветки, либо даже ниже него.В этом простом примере:

.highlight div {
    background-color: white;
}

Но на вашем реальном веб-сайте это может быть не так просто сделать.

1 голос
/ 19 ноября 2011

Управляйте всеми изменениями CSS в javascript, чтобы они были легко обратимыми.Как вы сказали, это невозможно в чистом CSS, но вы можете кэшировать стили с помощью javascript.

По шагам:

  1. определить, какие элементы будут игнорироваться внутри выделения
  2. проверьте, есть ли у вас фоновое изображение у любого из родителей
  3. , если у вас есть, сохраните изображение и этот элемент offset()
  4. захватите элементы-потомки
  5. сохранить их текущие стили CSS (до выделения)
  6. применить стили выделения к цели
  7. повторно применить сохраненные стилидля потомков
  8. , если был родитель с фоновым изображением, рассчитать и сместить изображение соответствующим образом

. При этом сохраняются все стили для внутренних элементов и учитываются фоновые изображения, которые«проваливаются» прозрачные фоны.

Вот тест: http://jsfiddle.net/W4Yfm/2/

Это оставляет грязное море атрибутов стиля, хотя, возможно, вы захотите его почистить.Вероятно, есть и неучтенные крайние случаи.

Чтобы быть наиболее надежным, вы должны использовать метод, подобный указанному @Jan (нарисуйте подсветку на холсте), но у вас не будет поддержки в IE <9, и этовероятно, слишком медленный для мобильного телефона. </p>

1 голос
/ 15 ноября 2011

"Фон сложен, потому что он эффективно действует, унаследованный, когда это не так. Но это все еще пример чего-то, что вызывает разрушение, которое я пытаюсь отрицать.: - /"

Неправильно. A , будучи элементом самого высокого уровня (самым старым предком), имеет фон. Когда последующие элементы происходят от A (например, B и C ), они имеют фон «прозрачный», что делает их унаследованным фоном (но именно поэтому ваши мозаичные фоны выглядят как смежные).

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

.highlight.bClass #c {
  background-image: url('http://hostilefork.com/shared/stackoverflow/parchment.jpg');
  background-repeat: repeat;
  color: initial;
}

Это дало бы иллюзию оригинального фона, всматривающегося в него, и, учитывая ваш пример, кажется почти безупречным невооруженным глазом. Это, однако, имеет неприятный побочный эффект, будучи совершенно не динамичным. Например, мы могли бы вместо этого создать новый класс:

.preventHighlight {
  background-image: url('http://hostilefork.com/shared/stackoverflow/parchment.jpg');
  background-repeat: repeat;
  color: initial;
}

И, кроме того, добавьте в свой javascript вторую строку:

$('#toggleHighlight').click(function(){
  $('#b').toggleClass('highlight');
  $('#c').toggleClass('preventHighlight');
});

Неплохо. Но что, если это, например, #x, который мы не хотим выделять? Я предлагаю дать #toggleHighlight новый атрибут name. В html попробуйте:

<button id="toggleHighlight" name="x">Toggle Highlight</button>

Где name="x" - это идентификатор элемента, к которому мы хотим применить класс preventHighlight. Таким образом, мы можем написать функцию более похожую на:

$('#toggleHighlight').click(function(){
  $('#b').toggleClass('highlight');
  $('#'+$('#toggleHighlight').attr('name')).toggleClass('preventHighlight');
});

Вы можете продолжить это, вместо этого создав функцию, принимающую два параметра, такие как tglHighlight ( idToHighlight , idToPrevent ) , если вы так склонны.

редактировать :

Я, кажется, неправильно понял @bozdoz и сделал по сути то же самое, не замечая видимого сдвига в фоне. Тогда я бы предложил небольшую альтернативу, которая включает коррекцию смещения фона. Это зависит исключительно от незначительного изменения в моем предложенном JavaScript:

$('#toggleHighlight').click(function(){
  $('#b').toggleClass('highlight');
  $('#'+$('#toggleHighlight').attr('name')).toggleClass('preventHighlight');
  $('.preventHighlight').css('background-position', function(index) {
    var ch_pos = $('.preventHighlight').position();
    var a_pos = $('#a').position();
    var x = a_pos.left-ch_pos.left;
    var y = a_pos.top-ch_pos.top;
    console.log( x+"px "+y+"px" );
    return x+"px "+y+"px";
  });
});
0 голосов
/ 19 ноября 2011

Хм, много предложений, но моей первой мыслью, которую я не проверял, было бы присвоить классу C те же теги, что и любое выделение, которое вы делаете для B, и сделать его важным!

Итак:

.cClass div { 
background-image: none !important; 
}
0 голосов
/ 18 ноября 2011

Я бы установил фон .cClass таким же, как .aClass с css, но если вы хотите, чтобы они совпали, вам придется также изменить стиль положения фона.

0 голосов
/ 15 ноября 2011

Проверьте это: http://jsfiddle.net/t63m7/

Это будет работать в вашем конкретном примере в jsFiddle.Возможно, вам придется поиграться с background-position в вашем реальном коде.

В этом случае нужно было добавить следующий CSS:

.highlight.bClass div {
    background-image: url('http://hostilefork.com/shared/stackoverflow/parchment.jpg');
    background-repeat: repeat;
    background-position: -84px 0;
}
0 голосов
/ 14 ноября 2011

Вы можете добавить .highlight .cClass в две верхние группы CSS и установить color:initial на .highlight .cClass, например, так:

.aClass, .highlight .cClass {
    background-image: url('http://hostilefork.com/shared/stackoverflow/parchment.jpg');
    background-repeat: repeat;
}

.aClass, .bClass, .cClass, .xClass, .highlight .cClass {
    border : 2px solid #000;
    margin: 20px;
    padding: 20px;
}

.highlight .cClass {
    color: initial;
}

Единственная проблема, в этом примере , то, что фоновая позиция изменяется.Но это лучшее, что я придумал.

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