Подтвердить что ты не робот

Обход проблемы из-за отсутствия функции CSS для "подавления унаследованных стилей" (и фона?)

У меня есть ситуация 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, изменение фона предка может изменить внешний вид потомков (если у них есть прозрачный фон). Таким образом, это пример того, что вызывает такое нарушение, которое я пытаюсь отрицать.: -/

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


UPDATE. Я создал базовый JsFiddle этого сценария, чтобы сделать обсуждение более ясным:

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

4b9b3361

Ответ 1

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

В шагах:

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

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

Здесь тест: http://jsfiddle.net/W4Yfm/2/

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

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

Ответ 2

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

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

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

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

Ответ 3

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

.highlight div {
    background-color: white;
}

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

Ответ 4

У меня есть решение, которое помогает с не связанными с фоном стилями. Вы можете увидеть скрипку http://jsfiddle.net/7ku3g/83/, которая представляет собой всего лишь взломанную концепцию. Некоторые ключевые моменты: 1) необходимо, чтобы добавленный элемент styleControl был добавлен во внутренний наиболее содержащий элемент. Например, у вас был класс .highlight, добавленный в div .bClass, но в нем был еще один полный элемент wrapper, 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 не содержат никакого содержимого (текст/изображения), они просто содержат другие элементы. Это "обертки" в моем использовании термина (они просто используются для группировки своих детей, хотя они могут иметь стиль).

Чтобы ответить на ваш вопрос о том, "когда деление нужно остановить", это когда вы достигнете точки, когда вам больше не нужны стили, наследующие. В приведенном выше примере необходимо добавить два элемента стиля: один на B0 и один на C0, но не на D0. Это связано с тем, что общий селектор sibling ~ применяется только к элементам, которые имеют один и тот же родительский элемент и которые следуют за этим братом. Таким образом, 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, которые обсуждаются (возможность создания родительских элементов из детей может быть использована для этой ситуации).

Ответ 5

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

Неправильно. 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";
  });
});

Ответ 6

Вы можете добавить .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;
}

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

Ответ 7

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

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

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

.highlight.bClass div {
    background-image: url('http://hostilefork.com/shared/stackoverflow/parchment.jpg');
    background-repeat: repeat;
    background-position: -84px 0;
}

Ответ 8

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

Ответ 9

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

Итак:

.cClass div { 
background-image: none !important; 
}