CSS для создания изогнутого угла между двумя элементами?

Мой пользовательский интерфейс имеет неупорядоченный список слева. Когда элемент списка выбран, справа от него появляется div. Я хотел бы иметь изогнутый внешний угол, где встречаются <li> и <div>. Некоторые люди называют это отрицательным радиусом границы или перевернутым углом. См. белую стрелку на изображении ниже.

пример изображения

Чтобы расширить синий <li> до края <ul>, я планирую сделать что-то вроде этого:

li { 
    right-margin: 2em; 
    border-radius: 8px; 
}

li.active { 
    right-margin: 0; 
    border-bottom-right-radius: 0; 
    border-top-right-radius: 0;
}

Есть ли лучший способ расширить <li> до края <ul>? Очевидно, я также включу CSS для webkit и mozilla border radius.

Главное, в чем я не уверен, так это в том, что внешний угол находится под нижним правым углом активного <li>. У меня есть некоторые идеи, но они кажутся хаками. Какие-либо предложения?

ЗАМЕЧАНИЕ, что <ul> обозначено серым цветом, но в реальном дизайне оно должно быть белым. Кроме того, я планирую использовать Javascript для правильного позиционирования <div> при выборе <li>.


person Tauren    schedule 05.01.2011    source источник
comment
Вы скопировали это с другого сайта? Как они это сделали?   -  person jcolebrand    schedule 05.01.2011
comment
Если он получил это с сайта, на котором они задавали тот же вопрос, и я не думаю, что вы можете инвертировать с помощью CSS, вам, возможно, придется прибегнуть к изображениям.   -  person RobertPitt    schedule 05.01.2011
comment
@drachenstern: Нет, я сделал это в фотошопе.   -  person Tauren    schedule 05.01.2011
comment
вопросы с фотошоп иллюстрациями получают от меня автоматически +1   -  person Paolo Bergantino    schedule 05.01.2011
comment
Вы всегда можете сказать, что вопрос хороший, если он включает в себя пользовательский рисунок.   -  person Evan Mulawski    schedule 05.01.2011
comment
Это связанный вопрос: stackoverflow.com/questions/4375978/   -  person methodofaction    schedule 07.01.2011


Ответы (6)


Ну, как оказалось, мне удалось решить проблему самостоятельно. Я собрал демо -- проверьте.

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

Я закончил с HTML следующим образом:

ul.selectable {
  padding-top: 1em;
  padding-bottom: 1em;
  width: 50%;
  float: left;
}
ul.selectable li {
  margin: 0 3em 0 4em;
  border-radius: 8px;
  -webkit-border-radius: 8px;
  -khtml-border-radius: 8px;
  -moz-border-radius: 8px;
}
ul.selectable li.active {
  margin-right: 0;
}
ul.selectable li.active dl {
  background-color: #4f9ddf;
}
ul.selectable li dt {
  background-color: #dfd24f;
  padding: 1em;
  margin-left: -2em;
  margin-right: -2em;
  -webkit-border-radius: 8px;
  -khtml-border-radius: 8px;
  -moz-border-radius: 8px;
  border-radius: 8px;
}
ul.selectable li dd {
  padding: 0.25em;
  background-color: #fff;
}
ul.selectable li.active dt {
  background-color: #4f9ddf;
  margin-right: 0;
  -webkit-border-top-right-radius: 0;
  -webkit-border-bottom-right-radius: 0;
  -khtml-border-top-right-radius: 0;
  -khtml-border-bottom-right-radius: 0;
  -moz-border-radius-topright: 0;
  -moz-border-radius-bottomright: 0;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
ul.selectable li.active dd.top {
  -webkit-border-bottom-right-radius: 8px;
  -khtml-border-bottom-right-radius: 8px;
  -moz-border-radius-bottomright: 8px;
  border-bottom-right-radius: 8px;
}
ul.selectable li.active dd.bot {
  -webkit-border-top-right-radius: 8px;
  -khtml-border-top-right-radius: 8px;
  -moz-border-radius-topright: 8px;
  border-top-right-radius: 8px;
}
div.right {
  float: left;
  padding-top: 3em;
  width: 50%;
}
div.content {
  height: 15em;
  width: 80%;
  background-color: #4f9ddf;
  padding: 1em;
  -webkit-border-radius: 8px;
  -khtml-border-radius: 8px;
  -moz-border-radius: 8px;
  border-radius: 8px;
}
<ul class="selectable">
  <li>
    <dl>
      <dd class="top"></dd>
      <dt>Title</dt>
      <dd class="bot"></dd>
    </dl>
  </li>
  <li class="active">
    <dl>
      <dd class="top"></dd>
      <dt>Title</dt>
      <dd class="bot"></dd>
    </dl>
  </li>
  <li>
    <dl>
      <dd class="top"></dd>
      <dt>Title</dt>
      <dd class="bot"></dd>
    </dl>
  </li>
</ul>
<div class="right">
  <div class="content">This is content</div>
</div>

Я не оптимизировал какой-либо CSS, так как просто взломал его. Но, возможно, это поможет кому-то еще. Я тестировал это только в Google Chrome на Mac OSX.

person Tauren    schedule 05.01.2011
comment
Поздравляю, вы собрали его вместе. Выглядит круто, и я собираюсь помнить об этом в будущем. - person jcolebrand; 05.01.2011
comment
@Yi Jiang: спасибо за исправление ошибок на jsfiddle. Я вставил, а потом забыл отделить... - person Tauren; 06.01.2011
comment
Я опубликовал новое решение, основанное на вашем коде, которое использует гораздо меньше кода и включает возможность использования gradient фона. - person ScottS; 14.07.2012

Более чистое решение (меньше кода и разрешен фоновый градиент)

См. скрипт (или другой), который использует этот HTML:

<ul class="selectable">
    <li>Title</li>
    <li class="active">Title</li>
    <li>Title</li>
    <li>Title</li>
</ul>
<div class="right">
    <div class="content">This is content</div>
</div>

И этот css (ключ состоит в том, чтобы позволить border-radius и border-width на псевдоэлементах сделать для вас перевернутый круг; я опустил код gradient.):

ul.selectable {
    padding-top: 1em;
    padding-bottom: 1em;
    width: 50%;
    float: left;
}
ul.selectable li {
    margin: 1em 1em 1em 2em;
    padding: 1em;
    border-radius: 8px;
    -webkit-border-radius: 8px;
    -khtml-border-radius: 8px;
    -moz-border-radius: 8px;
    background-color: #dfd24f;
    position: relative;
}
ul.selectable li.active {
    margin-right: 0;
    background-color: #4f9ddf;
    -webkit-border-top-right-radius: 0;
    -webkit-border-bottom-right-radius: 0;
    -khtml-border-top-right-radius: 0;
    -khtml-border-bottom-right-radius: 0;
    -moz-border-radius-topright: 0;
    -moz-border-radius-bottomright: 0;
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

ul.selectable li.active:before,
ul.selectable li.active:after {
    content: '';
    position: absolute;
    left: 100%; /* I use this instead of right: 0 to avoid 1px rounding errors */
    margin-left: -8px; /* I use this because I am using left: 100% */
    width: 8px;
    height: 8px;
    border-right: 8px solid #4f9ddf;
    z-index: -1;    
}

ul.selectable li.active:before {
    top: -8px;
    border-bottom: 8px solid  #4f9ddf;
    -webkit-border-bottom-right-radius: 16px;
    -khtml-border-bottom-right-radius: 16px;
    -moz-border-radius-bottomright: 16px;
    border-bottom-right-radius: 16px;
}
ul.selectable li.active:after {
    bottom: -8px;
    border-top: 8px solid  #4f9ddf;
    -webkit-border-top-right-radius: 16px;
    -khtml-border-top-right-radius: 16px;
    -moz-border-radius-topright: 16px;
    border-top-right-radius: 16px;
}
div.right {
    float: left;
    padding-top: 3em;
    width: 50%;
}
div.content {
    height: 15em;
    width: 80%;
    background-color: #4f9ddf;
    padding: 1em;
    -webkit-border-radius: 8px;
    -khtml-border-radius: 8px;
    -moz-border-radius: 8px;
    border-radius: 8px;
}
person ScottS    schedule 14.07.2012

Я придумал решение, которое требует меньше разметки. Таким образом, вместо использования полей используются белые закругленные границы, затем мы размещаем активный li за белыми закругленными границами, чтобы добиться эффекта инвертированного радиуса границы.

http://jsfiddle.net/zrMW8/

<ul class="selectable">
    <li>
        <a href="#">Title</a>
    </li>
    <li class="active">
        <a href="#">Title</a>
    </li>
    <li>
        <a href="#">Title</a>
    </li>
    <li>
        <a href="#">Title</a>
    </li>
</ul>
<div class="right">
    <div class="content">This is content</div>
</div>

И меньше CSS тоже! (это сводит с ума):

a { color: #000; text-decoration: none;}

ul.selectable {
    padding: 1em 1em;
    width: 40%;
    float: left;
}

ul.selectable li {
    margin:  -1em 0 0 0;
    border-radius: 8px;
    -webkit-border-radius: 8px;
    -khtml-border-radius: 8px;
    -moz-border-radius: 8px;
    border: solid #fff 1em;
    position: relative;
}

ul.selectable li a {
   background-color: #dfd24f;
    padding: 1em;
    display: block;
       border-radius: 8px;
    -webkit-border-radius: 8px;
    -khtml-border-radius: 8px;
    -moz-border-radius: 8px;
}

ul.selectable li.active {
    margin: -1em -1em -1em 1em;
    border: solid #4f9ddf 1em;
    border-left: solid #fff 1em;
    background-color: #4f9ddf;
    position: static;
}

ul.selectable li.active a {
    margin: 0 0 0 -1em;
    border-left: solid #4f9ddf 1em;
    background-color: #4f9ddf;
    position: static;
    text-indent: -1em;
}

div.right {
    float: left;
    padding-top: 3em;
    width: 50%;
    margin-left: -1em;
}
div.content {
    height: 15em;
    width: 80%;
    background-color: #4f9ddf;
    padding: 1em;
    -webkit-border-radius: 8px;
    -khtml-border-radius: 8px;
    -moz-border-radius: 8px;
    border-radius: 8px;
}

По правде говоря, я не уверен, что это лучшая версия, она упрощает создание градиентного фона/изображения (по крайней мере, для неактивных ли), но вы не можете применить фоновое изображение/градиент к телу. Это также «плохая магия» в том смысле, что она работает неинтуитивно.

person methodofaction    schedule 07.01.2011

Не совсем, извините, за

Инвертировать закругленный угол в CSS?

person Ben    schedule 05.01.2011

Чтобы сделать это поверх нетвердого bg, я не думаю, что вы можете сделать это с помощью CSS, но вы можете использовать холст или SVG для того же эффекта - хотя это не совсем то, что вы просили.

Однако есть предложение по отрицательному радиусу границы, которое решит проблему проблема. Может быть, когда-нибудь, да.

person Russell Leggett    schedule 05.01.2011
comment
Я почти уверен, что он сделал это с помощью CSS, как и хотел. Я не уверен, что означает ваш ответ. - person jcolebrand; 05.01.2011
comment
Я согласен с тем, что использование холста или SVG, вероятно, единственный способ сделать это на не сплошном фоне. - person Tauren; 06.01.2011

Это прекрасное инструкция по обратному радиусу границы в CSS может помочь. Объясняет, как сделать обратный радиус границы для вкладок. Но его можно легко адаптировать для оптимизации вашего CSS, поскольку он использует :after вместо создания слишком большого количества дополнительных элементов.

person Jon Mifsud    schedule 14.07.2012