Destacar los comentarios del autor (jQuery para localizar ascendientes) | Oloblogger Con el sistema de anidados actualmente es complicado -por no decir imposible- modificar con CSS el a...

27 de junio de 2013

Destacar los comentarios del autor (jQuery para localizar ascendientes)

Con el sistema de anidados actualmente es complicado -por no decir imposible- modificar con CSS el aspecto del bloque completo de los propios comentarios. El motivo es que salvo por un selector bautizado como blog-author, que es el único que marca los comentarios del autor del post, no hay manera de llegar a esos comentarios para darles estilo.

El problema es que ese selector sólo afecta a la cabecera del comentario, es decir, a una sección dónde sólo encontramos el nick y la fecha, por lo que si aplicamos reglas ahí, sólo nos cambiará esa cabecera y no todo el bloque del comentario que es lo que a veces deseamos.

En un anterior post se explicó cómo hacer eso que sí que es sencillo, consiguiendo cambiar el icono que acompaña a nuestro nick y algunas modificaciones en la tipografía. Ahora lo que haremos será modificar todo el bloque, pero recurriendo a jQuery.


Aquellos que sólo precisen el código y no necesiten ninguna explicación, por favor pasen de manera ordenada al final del post. Gracias. Les deseamos un feliz viaje :)


La estructura de los comentarios anidados de Blogger


Me voy a apoyar en este esquema para que me sea más fácil explicar dónde está el problema y cómo se soluciona.

Estructura comentarios Blogger

Como veis, Blogger monta cada comentario con una serie de elementos independientes.

Cada grupo comentario+respuestas van dentro de un elemento de una lista (ol) en la que el primer comentario es un elemento normal (li) y las respuestas se almacenan dentro de una segunda lista anidada en la primera (ol li ol li). Tanto la principal como la anidada llevan la clase .comment (bloque rojo).

Luego, para formar cada comentario (o respuesta) hay dos cajas, la del avatar (verde) y la que llevará el resto de datos (.comment-block, azul). A su vez, dentro de esta última tendremos una cabecera (.comment-header, púrpura) y un cuerpo de texto (.comment-content, amarillo).

En el dibujo utilicé la respuesta para marcar estas dos últimas clases con colores, sólo por cuestión de falta de espacio pero como dije, realmente estarían dentro del bloque azul. Para cada bloque comentario/respuestas la estructura se repetiría.

Esto mismo codificado, o lo que es lo mismo, su estructura HTML, sería así para un comentario y su primera respuesta. He omitido algunas partes que para lo de hoy no nos interesan.

<ol> <!-- Bloque comentarios y sus respuestas -->
  <li class='comment'> <!-- Comentario -->
    <div class="avatar-image-container">...</div>
    <div class="comment-block">
      <div class='comment-header><cite class="user">...</cite>
         ...
      </div>
      <div class='comment-content>...</div>
    </div>
  </li>
  <li>
    <ol> <!-- Respuestas -->
      <li class='comment'> <!-- Primera respuesta -->
        <div class="avatar-image-container">...</div>
          <div class="comment-block">...</div>
            <div class='comment-header>
              <cite class="user blog-author">...</cite>
              ...
            </div>
            <div class='comment-content>...</div>
          </div>
        </div>
      </li>
      <li class='comment'> <!-- Segunda respuesta -->
      etc.

Obsérvese que la primera respuesta tiene en el tag cite un blog-author. Ese selector lo inserta Blogger automáticamente, pero sólo cuando el comentario/respuesta en cuestión es del autor del post. Esa es nuestra clave... y también el problema.


Centrando el problema


Nosotros necesitamos dar estilo a .comment-block, pero no a todas las cajas con ese selector, sino sólo y necesariamente a los que DESPUÉS tengan un .comment-header que a su vez incluya un .blog-author.

Como vimos en anteriores entradas, CSS va en sentido descendente por lo que puedo dar estilo sin problemas a un selector que tenga determinado padre:

(Las reglas se aplican a las cajas marcadas con blog-author que sean hijas de comment-header y nietas de li.comment)
li.comment .comment-header .blog-author {reglas}

Pero no puedo hacer nada para que un determinado li.comment tenga determinadas reglas sí y sólo si uno de sus hijos tiene un blog.author. No sé, en caso de que existiera sería algo así, pero insisto en que esto no es interpretable... si acaso lo aporto como idea para cuando saquen CSS4 ;)

li.comment  {reglas} .comment-header .blog-author

Esto que es muy evidente para cualquiera que controle un mínimo las bases de CSS es obvio, pero para mí que sólo aprendo a golpes, el llegar a esta conclusión me ha costado muchos cabezazos contra la pared, así que ahí queda explicado para que otros no perdáis el tiempo lastimosamente como un servidor.


La solución: Localizar ascendientes con jQuery y marcarlos


Como decía anteriormente, lo que nosotros necesitamos es localizar las cajas li.comment que tengan dentro (descendientes) alguna clase blog.author y si bien con CSS no se puede hacer, con jQuery está chupado porque existe un selector llamado :has() que precisamente hace eso.

:has() | Selecciona elementos que contienen al menos un elemento que coincida con el selector especificado.

(Seleccionar aquellos div que tengan como descendientes (directos o no) un párrafo )
$('div:has(p)')

Pero con esto sólo los localizamos. Para poder dar estilo tranquilamente desde CSS, un sistema podría ser añadirle determinada clase especial creada ad hoc para que se quede algo así:

...
  <li>
    <ol> <!-- Respuestas -->
      <li class='comment ESPECIAL'> <!-- Primera respuesta -->
        <div class="avatar-image-container">...</div>
          <div class="comment-block">...</div>
            <div class='comment-header>
              <cite class="user blog-author">...</cite>
              ...

De esta maner luego podríamos hacer esto otro:

li.comment.ESPECIAL {reglas}


Como :has() selecciona cualquier caja que tenga el selector buscado y esto no nos interesa porque en determinados casos nos tomaría no sólo nuestros comentarios, sino todos los que estén a continuación aunque no sean nuestros, echamos mano adicionalmente de un segundo selector jQuery:

.closest() | Para cada elemento en el bloque, selecciona el PRIMER elemento que coincide con el selector indicado comprobando dentro y hacia arriba (ascendientes) en el árbol DOM.

Más información sobre .closest() en la página del enlace.


El código


Lo primero es cargar la librería jQuery desde nuestra plantilla. Si no se dispone de ella hay que insertar una línea como esta antes de </head>:

<script src='http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js' type='text/javascript'/>

A continuación agregamos las instrucciones que hemos visto antes más otra que añadirá una clase con nombre comenautor al elemento de lista seleccionado, que es ni más ni menos el que tenga dentro una caja con la clase blog-author. Con esto ya tendremos nuestros propios comentarios marcados con esa clase (comenautor).

<script type='text/javascript'>
  //<![CDATA[
  $(document).ready(function() {
    $(".blog-author").closest("li.comment").addClass("comenautor");
  });
//]]>
</script>

¿Qué queda? Pues ya sólo añadir en nuestro CSS (entre las etiquetas skin) el estilo que queramos para los distintos elementos que hay dentro de esa lista, esos que vimos en el esquema del principio. Por ejemplo esto cambia el color de fondo y el borde de todo el bloque y del avatar. Del nuestro, por cierto.

<style type='text/css'>
  li.comment.comenautor > .comment-block,
  li.comment.comenautor > .avatar-image-container {
    background-color: #FDFAEC;
    border-color: #FCF7DC;
  }
</style>


Cambiando clases y reglas, podréis conseguir más efectos. Otro por ejemplo podría ser hacer más grande el propio avatar:

li.comment.comenautor > .avatar-image-container,
li.comment.comenautor > .avatar-image-container img {
width: 80px;
height: 80px;
}

O quizás ponerle una marca al bloque entero:

.comment.comenautor > .comment-block {
position: relative;
}
.comment.comenautor > .comment-block:after {
content: "\2716";
position: relative;
top: 0;
right: 0;
font-size: 30px;
color: blue;
}


Mucho más fácil hacerlo que explicarlo. Como casi siempre.

¿Vemos otro post al azar por si le encuentras utilidad o quizás prefieres ser más metódico y suscribirte a nuestras entradas por correo? También puedes imprimir este artículo y por supuesto compartirlo en redes sociales si fue de tu agrado.

Compartir
Copy URL

Y muchos más artículos interesantes si nos sigues en...

follow us in feedly

43 comentarios :

  1. Muchas gracias Oloman.
    Tus explicaciones son siempre tan claras que hasta las más torpes podemos hacer que parezca lo controraio. Aunque no sé que demonios de casilla tengo activada que en los comentarios que dejo por ahí, me sale la dichosa señal de tráfico (puñetera)
    de dirección prohibida.
    ¿Qué será lo que tengo prohibido en G?

    Mina

    ResponderEliminar
    Respuestas
    1. No sé, pero puedes probar a reiniciar que en informática es una solución universal. Vuelve a cargar tu avatar en tu perfil de Blogger y luego haz lo propio con el de Google Plus. También comprueba que la cuenta con la que te logueas tiene el mismo avatar y en cualquier caso, lo vuelves a subir.

      Eliminar
    2. He comprobado y hecho todo lo que me dices. Algunas cosas ya las había comprobado antes más de una vez. Ahora, he puesto en mi perfil blogger la misma url de la foto de perfil Google+. Cruzaré los dedos....

      Eliminar
    3. Bueno..bueno..., No te beso porque no puedo, pero de todas formas ahí vá...MUAC.
      Mil gracias Oloman y un saludo.

      Eliminar
    4. Por si el comentario anterior está censurado, aquí va éste..

      Bueno..., bueno...!

      Mil gracias Oloman.

      Eliminar
  2. En hora buena se te ha ocurrido esta solución (creo que única y pionera) para algo que debería ser tan sencillo de hacer como sólo declarar un par de reglas css... pero es blogger (google) y su generosidad en regalarnos divs y más divs y más divs a lo loco.
    Ni que cobrasen por etiqueta creada.

    Lo siguiente, y ya te pongo un altarcito con flores y velas, es un input tipe="killer" para sus iframes y anidamientos de divs.

    Un saludo

    ResponderEliminar
    Respuestas
    1. Lo complicado precisamente es descifrar el anidamiento de clases, pero no creo que la solución sea tan pionera. A alguien más seguro que se le ocurrió algo parecido.

      Eliminar
  3. Si, desde luego eres un pionero con esta idea, porque otras alternativas no han funcionado bien....

    Por cierto, una cosa que me atrajo mucho la atención: como podría sustituir el "lápiz" (imagen en base64 del autor) por un content: "\2716" ¿?¿?

    Por que yo soy de los que hago las cosas a lo bestia, y sustituyendo de forma bruta el background-image: del .comments .comments-content .icon.blog-author { no me deja... :S

    Espero con ganas tu respuesta :)

    Buen post, sigue asi!

    Salu2

    ResponderEliminar
    Respuestas
    1. Eso es fácil Valentín:
      .user.blog-author:after {
      content: "\2716";
      }

      Eliminar
  4. Oloman!, tengo un problema, blogger ahora no permite publicar entradas sin titulo. Nos aparece un cartel que dice: " Required field must not be blank" y no nos permite omitir dicha advertencia. Como solución encontré poner en el titulo un espacio. Haciendo eso me deja guardar la nota, pero cuando la publico me aparece el "publicado por" aun así cuando tengo seleccionado la opción "no permitir comentarios", esto me arruina el diseño, antes no me pasaba, se te ocurre alguna forma de solucionar esto?

    Esperare ansioso tu respuesta! Saludos, y te dejo un ejemplo donde me surgio el problema. http://elpendrivedebocha.blogspot.com.ar/search/label/Canciones

    ResponderEliminar
    Respuestas
    1. No entiendo dónde está el problema de diseño Bocha, pero si lo que quiere es que no aparezca ese "Publicado por...", añade a tu CSS esto:
      .post-author {display: none;}

      Eliminar
  5. Quiero hacer que el "publicado por..." no aparezca pero solo en las entradas que tienen seleccionada la opcion de: no permitir comentarios. Se puede?

    ResponderEliminar
    Respuestas
    1. En algún sitio de tu plantilla tienes que tener un trozo de código como este que es el que genera el Publicado por con el nombre del autor del post. Tienes que añadir la primera y última línea que he añadido yo, que es una condición para comprobar si la entrada tienes permitido mostrar comentarios o no.

      <b:if cond='data:post.allowComments'>
      <span class='post-author vcard'>
      <b:if cond='data:top.showAuthor'>
      <data:top.authorLabel/>
      <b:if cond='data:post.authorProfileUrl'>
      <span class='fn'>
      <a expr:href='data:post.authorProfileUrl' rel='author' title='author profile'>
      <data:post.author/>
      </a>
      <span class='updated'>
      <abbr class='published' expr:title='data:post.timestampISO8601'>
      <data:post.timestamp/>
      </abbr>
      </span>
      </span>
      <b:else/>
      <span class='fn'>
      <data:post.author/>
      </span>
      <span class='updated'>
      <abbr class='published' expr:title='data:post.timestampISO8601'>
      <data:post.timestamp/>
      </abbr>
      </span>
      </b:if>
      </b:if>
      </span>

      </b:if>

      Eliminar
    2. Recién le agregue esas lineas que me dijiste, guardo la plantilla, me fijo si quedo y nada. Sigue igual.

      Antes me andaba lo mas bien, pero desde que blogger no permite publicar posts sin títulos, dejo de andar, ¿no sabes que puede ser?

      Eliminar
    3. Lo que dices, en un principio, no debe tener nada que ver. No lo recuerdo ahora mismo, pero puede que haya dos trozos de código como ese, uno para la plantilla de móviles y otra para plantilla web (normal). Busca y si hay un segundo trozo, prueba con él.

      Eliminar
    4. Se acaba de arreglar, muchas gracias Oloman!!!

      Eliminar
  6. Hola Oloman, recurro a ti para intentar aclarar una duda que tengo con el jQuerry. Verás, necesito conseguir ocultar los comentarios cuando haga click sobre una imagen (concretamente, ocultar el <div id="comments" class="comments">)

    Si añado este CSS:

    #comments {
    display: block;
    }


    Luego puedo modificar el valor display de block a none para ocultarlo, y funciona perfectamente.

    Sin embargo, cuando agrego esta función de jQuerry (es la parte fundamental de todo el código):

    $('#comments').css('display','none');
    $('#comments-norm').removeClass('comment-on');


    No cumple su función.... He probado aplicarlo CON y SIN el fragmento de CSS. Cuando doy click sobre la imagen, los comentarios no desaparecen... Sin embargo, cuando cambio el CSS manualmente, desaparece perfectamente.

    Se te ocurre que puede ser¿?

    Muchas gracias por adelantado, sigue así con tu Blog!!

    Salu2

    ResponderEliminar
    Respuestas
    1. Necesitaría ver el código completo para ver dónde puede estar el problema, pues tiene pinta de ser sólo un error de sintaxis. De todas formas puedes usar lo que explico en el apartado 2 de esta entrada que precisamente hace lo que quieres. Sólo tienes que ver cómo construí el enlace y luego cambiar el texto que hace de botón, por una imagen.

      Eliminar
    2. Acabo de aplicar tu entrada a mi blog y sigue con lo mismo... :(

      Cuando pulso COMENTARIOS GPLUS, se despliega y se muestra perfectamente. Sin embargo, cuando pulso sobre COMENTARIOS CLÁSICOS volvemos a lo mismo, la propiedad display del elemento #comments no se cambia... Yo ya estoy desesperado, no sé que hacer! :(

      PD: Originalmente quería aplicar esto a mi Blog:

      goo.gl/DqNsk

      PD2: Ya de paso, te lo ofrezco como una inspiración mas para tu blog... jejeje :)

      Salu2

      Eliminar
    3. No sé qué puede andar mal en el código de tu plantilla para que funcione uno sí y el otro no, pero es muy raro. Si lo vuelves a poner quizás pueda encontrar el problema, aunque tardaré un poco en verlo porque en esta época del año voy a paso de tortuga... coja. De todas formas mientras yo lo veo te da tiempo de arreglar tu pestaña lateral de Twitter, pues no muestra contenido. Mira esto por si acaso es tu problema.

      Eliminar
    4. Muchas gracias, como siempre una info muy útil!!

      Salu2

      Eliminar
  7. Este comentario ha sido eliminado por un administrador del blog.

    ResponderEliminar
    Respuestas
    1. ¿Que tiene que ver esto con lo que se habla en este blog? ¡No hagas spam!

      Eliminar
    2. Exacto, pero para algo algunos tenemos PODERES de administrador ;)

      Eliminar
    3. No estoy seguro, pero me parece que es un sistema publicitario en el que actúas como un bot (haciendo propaganda) a cambio de algo (dinero seguramente)...

      Lo digo porque la estructura del mensaje es la misma que la que me ponen a mí en el blog a veces (y lo más gracioso, siempre en la misma entrada) xD

      Salu2

      Eliminar
    4. para que no aparescan cosas que no quieren xD, mejor pongan la opcion de moderar comentarios :3, si nos aparecen cosas raras las borramos sin que nadie las haya visto xDD LOL

      Eliminar
    5. Para mí es muy incómodo moderar los comentarios porque tengo muchos. Prefiero ir borrando los que resultan ser spam o similar

      Eliminar
  8. hola!... entonces... ahm... lo que tengo que copiar es la libreria y el script que le sigue y ya?? bueno, ya no necesito urgente el truco pues ya cambie el estilo del blog... pero es bueno saberlo ;3 gracias

    ResponderEliminar
    Respuestas
    1. La mayoría del post es para explicar cómo monta los comentarios Blogger (por si hay que hacer otra chapuza) y los inconvenientes de CSS para seleccionar ascendentes. Para hacer lo que el título de esta entrada promete, basta con la parte que hay bajo el subtítulo "El código".

      Eliminar
  9. Hola como estas Oloman tengo un inconveniente todo me salio perfecto pero el único problema es que las respuesta del autor no se me modifica.

    Puedes Verlo en este Link http://www.diakchimba.com/2012/03/windows-7-sp1-todas-las-versiones-de-32.html

    ResponderEliminar
    Respuestas
    1. Entonces no salió perfecto, sino justo al contrario :)

      De todas formas ya vi que aplicaste otro truco con esa etiqueta roja.

      Eliminar
  10. si así es, ni modo, hay me avisas si tienes alguna solución.

    Saludes y Gracias Oloman

    ResponderEliminar
  11. Hecho y funcionando, pero con un detalle. Tengo una modificación para mostrar los comentarios con colores alternados, y uno distinto en las respuestas, forzando cambios en los colores de fondo. Por eso, con este método puedo cambiar el borde y otras cosas, pero no el color de fondo de forma que se aplique a comentarios y respuestas.

    De todas formas, un gran truco al que le tenía ganas desde hace tiempo. Gracias :)

    ResponderEliminar
    Respuestas
    1. No sé qué código será ese que pusiste, pero el color de fondo del autor lo deberías poder cambiar de la forma que expliqué en cualquier caso. Y si es que el CSS de ambos se solapa, prueba a añadir !important a las reglas del estilo para el autor.

      Eliminar
    2. Es algo como esto, simplificado:
      .comments .comments-content .comment { /* comentarios pares */
      background-color: #FAFAFA;
      border: 1px solid Gray;
      }
      .comments .comments-content .comment:nth-child(2n+1) { /* comentarios impares */
      background-color: #F2F2F2;
      border: 1px solid Gray;
      }
      .comments .comments-content .comment-thread ol li ol li { /* fondo para todas las respuestas */
      background-color: OldLace !important;
      }

      El problema es que la respuesta ya fuerza un color de fondo distinto con !important, y por eso auqnue lo fuerce otra vez para las respuestas del autor aplica el estandar para todas las respuestas. Supongo que hay una forma de arreglarlo, pero se me escapa. Con el borde no hay problema porque no lo fuerzo para las respuestas, sino solo para el autor.

      Eliminar
    3. En lugar de poner li.comment.comenautor > .comment-block como yo expliqué, sé más concreto y usa
      .comments .comments-content .comment-thread ol li ol li.comment.comenautor > .comment-block {}

      Y en cualquier caso, que eso del autor vaya en la plantilla después de los estilos que tú pusiste.

      Eliminar
    4. Pues tras hacer unas pruebas, me ha funcionado con lo siguiente:

      li.comment.comenautor {
      background-color: MintCream !important;
      border: solid OliveDrab 2px !important;
      }
      .comment-thread ol li ol li.comment.comenautor { /* extra para fondo de respuestas */
      background-color: MintCream !important;
      }
      li.comment.comenautor > .avatar-image-container {
      border: solid Black 1px;
      }

      Cada vez que veo lo de "ol li ol li" me mareo, pero me alegro de que funcione. Everybody praise Oloman!

      Eliminar
    5. Para evitar futuros mareos, date una vuelta por este post y el siguiente de Avanzados ;)

      Eliminar
    6. Sí que los leí, y con atención además. Pero es ver eso de "ol li ol li" y venirme la imagen de unas patatas fritas a la cabeza. No sé por qué será ;)

      Eliminar
  12. ¿Hay alguna forma de conseguirlo sin jQuery, solo con javascript puro? Es que no quiero sobrecargar mi blog con scripts y librerías grandes para un efecto tan simple pero efectivo...

    ResponderEliminar
  13. Jorge, el efecto es precisamente simple porque se apoya en jQuery. Esta librería tiene unas 56 KB y por eso es bastante usada. Una vez instalada podrás simplificar muchos de tus scripts y quizás aligerar eso mismo que ahora sobrecargas.

    ResponderEliminar