Selectores CSS

Avanzado
Selenium
Selenium
Actualizado: 05/09/2025

¡Desbloquea el curso de Selenium completo!

IA
Ejercicios
Certificado
Entrar

Mira la lección en vídeo

Accede al vídeo completo de esta lección y a más contenido exclusivo con el Plan Plus.

Desbloquear Plan Plus

Selectores CSS básicos

Los selectores CSS representan una de las formas más eficientes y legibles de localizar elementos en el DOM durante la automatización de pruebas web. Selenium WebDriver implementa el método By.cssSelector() que permite utilizar la misma sintaxis CSS que emplean los navegadores para aplicar estilos, pero adaptada para la localización de elementos.

La ventaja principal de los selectores CSS radica en su naturaleza intuitiva para desarrolladores web y su excelente rendimiento de ejecución. Al utilizar la misma sintaxis que CSS, resulta familiar para quienes han trabajado con hojas de estilo, facilitando la curva de aprendizaje.

Selectores fundamentales

Los selectores básicos constituyen la base de cualquier estrategia de localización CSS. Cada tipo de selector se enfoca en diferentes atributos del elemento HTML.

Selector por ID

El selector por ID utiliza el símbolo # seguido del valor del atributo id del elemento. Este selector es altamente específico y debería localizar un único elemento, ya que los IDs deben ser únicos en el DOM.

@Test
void testSelectorPorId() {
    WebElement elemento = driver.findElement(By.cssSelector("#usuario"));
    elemento.sendKeys("admin@ejemplo.com");
}

Selector por clase

El selector de clase emplea el símbolo . seguido del nombre de la clase CSS. Es importante recordar que un elemento puede tener múltiples clases, y este selector localizará cualquier elemento que contenga la clase especificada.

@Test
void testSelectorPorClase() {
    List<WebElement> botones = driver.findElements(By.cssSelector(".btn-primary"));
    botones.forEach(WebElement::click);
}

Selector por elemento

Este selector utiliza directamente el nombre de la etiqueta HTML sin ningún símbolo adicional. Resulta útil cuando necesitamos localizar todos los elementos de un tipo específico.

@Test
void testSelectorPorElemento() {
    List<WebElement> enlaces = driver.findElements(By.cssSelector("a"));
    long enlacesVisibles = enlaces.stream()
        .filter(WebElement::isDisplayed)
        .count();
}

Selectores de atributo

Los selectores de atributo permiten localizar elementos basándose en la presencia o valor específico de sus atributos HTML. Proporcionan una flexibilidad considerable cuando los selectores básicos no son suficientes.

Selector por presencia de atributo

Localiza elementos que poseen un atributo específico, independientemente de su valor:

@Test
void testSelectorPorAtributo() {
    List<WebElement> camposRequeridos = driver.findElements(By.cssSelector("[required]"));
    assertThat(camposRequeridos).isNotEmpty();
}

Selector por valor exacto de atributo

Busca elementos cuyo atributo coincida exactamente con el valor especificado:

@Test
void testSelectorPorValorAtributo() {
    WebElement campoEmail = driver.findElement(By.cssSelector("[type='email']"));
    campoEmail.sendKeys("usuario@dominio.com");
}

Combinadores básicos

Los combinadores CSS permiten crear selectores más específicos estableciendo relaciones entre elementos en la estructura del DOM. Estos combinadores son fundamentales para localizar elementos en contextos específicos.

Combinador descendiente (espacio)

Un espacio entre selectores indica una relación descendiente, donde el segundo elemento debe estar contenido dentro del primero, sin importar el nivel de anidamiento:

@Test
void testCombinadorDescendiente() {
    WebElement boton = driver.findElement(By.cssSelector("div.formulario button"));
    boton.click();
}

Combinador hijo directo (>)

El símbolo > especifica que el segundo elemento debe ser hijo directo del primero, es decir, no puede haber elementos intermedios:

@Test
void testCombinadorHijoDirecto() {
    List<WebElement> itemsMenu = driver.findElements(By.cssSelector("nav > ul > li"));
    itemsMenu.get(0).click();
}

Combinador hermano adyacente (+)

El símbolo + localiza el elemento inmediatamente siguiente que sea hermano del elemento de referencia:

@Test
void testCombinadorHermanoAdyacente() {
    WebElement etiquetaSiguiente = driver.findElement(By.cssSelector("input[type='checkbox'] + label"));
    etiquetaSiguiente.click();
}

Combinador hermanos generales (~)

El símbolo ~ selecciona todos los elementos hermanos que siguen al elemento de referencia, no necesariamente de forma inmediata:

@Test
void testCombinadorHermanosGenerales() {
    List<WebElement> camposSiguientes = driver.findElements(By.cssSelector("h2 ~ input"));
    camposSiguientes.forEach(campo -> campo.clear());
}

Combinación de selectores

La combinación de múltiples selectores permite crear expresiones más precisas y específicas. Esta técnica resulta especialmente útil cuando trabajamos con páginas complejas donde un solo selector podría ser ambiguo.

@Test
void testSelectoresCombinados() {
    // Combinar clase y atributo
    WebElement botonEnviar = driver.findElement(By.cssSelector("button.btn-success[type='submit']"));
    
    // Combinar ID y descendiente
    WebElement campoNombre = driver.findElement(By.cssSelector("#formulario-registro input[name='nombre']"));
    
    // Múltiples clases
    WebElement alerta = driver.findElement(By.cssSelector(".alert.alert-danger"));
}

La sintaxis CSS ofrece una flexibilidad considerable para adaptar los selectores a las necesidades específicas de cada caso de prueba. La clave está en encontrar el equilibrio entre especificidad y mantenibilidad, creando selectores que sean lo suficientemente precisos para localizar el elemento correcto, pero no tan específicos que se rompan fácilmente ante cambios menores en la estructura del DOM.

Selectores CSS avanzados

Guarda tu progreso

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

Los selectores CSS avanzados amplían significativamente las capacidades de localización, permitiendo crear estrategias más sofisticadas para elementos complejos o dinámicos. Estos selectores resultan especialmente valiosos cuando trabajamos con aplicaciones web modernas que generan contenido dinámico o estructuras DOM complejas.

La potencia de los selectores avanzados reside en su capacidad para adaptarse a patrones específicos del DOM, proporcionando alternativas robustas cuando los selectores básicos no ofrecen la precisión necesaria.

Pseudo-clases estructurales

Las pseudo-clases estructurales permiten seleccionar elementos basándose en su posición relativa dentro de su contenedor padre. Estas pseudo-clases son fundamentales para localizar elementos en listas, tablas o cualquier estructura repetitiva.

Selector :nth-child()

La pseudo-clase :nth-child() localiza elementos según su posición específica entre sus hermanos. Acepta números, palabras clave o fórmulas matemáticas:

@Test
void testNthChild() {
    // Seleccionar el tercer elemento de una lista
    WebElement tercerItem = driver.findElement(By.cssSelector("ul li:nth-child(3)"));
    
    // Seleccionar elementos pares usando fórmula
    List<WebElement> filasPares = driver.findElements(By.cssSelector("table tr:nth-child(even)"));
    
    // Seleccionar cada tercer elemento usando fórmula
    List<WebElement> cadaTercero = driver.findElements(By.cssSelector(".producto:nth-child(3n)"));
}

Selectores :first-child y :last-child

Estas pseudo-clases localizan respectivamente el primer y último elemento hijo dentro de su contenedor:

@Test
void testFirstLastChild() {
    WebElement primerElemento = driver.findElement(By.cssSelector(".menu li:first-child"));
    WebElement ultimoElemento = driver.findElement(By.cssSelector(".menu li:last-child"));
    
    // Combinar con otros selectores para mayor especificidad
    WebElement primerBoton = driver.findElement(By.cssSelector("form button:first-child"));
}

Selector :nth-of-type()

Esta pseudo-clase selecciona elementos según su posición entre elementos del mismo tipo:

@Test
void testNthOfType() {
    // Seleccionar el segundo párrafo dentro de un div
    WebElement segundoParrafo = driver.findElement(By.cssSelector("div p:nth-of-type(2)"));
    
    // Seleccionar el último input de tipo text
    WebElement ultimoInput = driver.findElement(By.cssSelector("input[type='text']:last-of-type"));
}

Pseudo-clases de estado

Las pseudo-clases de estado permiten localizar elementos basándose en su estado actual en la interfaz de usuario. Estas pseudo-clases son especialmente útiles para validaciones y verificaciones dinámicas.

@Test
void testPseudoClasesEstado() {
    // Localizar elementos habilitados
    List<WebElement> camposHabilitados = driver.findElements(By.cssSelector("input:enabled"));
    
    // Localizar elementos deshabilitados
    List<WebElement> camposDeshabilitados = driver.findElements(By.cssSelector("input:disabled"));
    
    // Localizar checkboxes marcados
    List<WebElement> checkboxesMarcados = driver.findElements(By.cssSelector("input[type='checkbox']:checked"));
}

Selectores de atributo avanzados

Los selectores de atributo avanzados ofrecen capacidades de coincidencia de subcadenas, permitiendo localizar elements basándose en patrones específicos dentro de los valores de sus atributos.

Selector de contiene subcadena (*=)

El operador *= localiza elementos cuyo atributo contiene la subcadena especificada en cualquier posición:

@Test
void testAtributoContiene() {
    // Localizar elementos cuya clase contiene "button"
    List<WebElement> botones = driver.findElements(By.cssSelector("[class*='button']"));
    
    // Localizar inputs cuyo name contiene "email"
    WebElement campoEmail = driver.findElement(By.cssSelector("input[name*='email']"));
}

Selector comienza con (^=)

El operador ^= selecciona elementos cuyo atributo comienza con la cadena especificada:

@Test
void testAtributoComienza() {
    // Localizar elementos cuyo ID comienza con "form"
    List<WebElement> formularios = driver.findElements(By.cssSelector("[id^='form']"));
    
    // Localizar enlaces que comienzan con "https"
    List<WebElement> enlacesSegures = driver.findElements(By.cssSelector("a[href^='https']"));
}

Selector termina con ($=)

El operador $= localiza elementos cuyo atributo termina con la cadena especificada:

@Test
void testAtributoTermina() {
    // Localizar elementos cuya clase termina con "error"
    List<WebElement> camposError = driver.findElements(By.cssSelector("[class$='error']"));
    
    // Localizar imágenes PNG
    List<WebElement> imagenesPng = driver.findElements(By.cssSelector("img[src$='.png']"));
}

Selectores de negación

El selector de negación :not() permite excluir elementos que coincidan con el selector especificado dentro de los paréntesis:

@Test
void testSelectorNegacion() {
    // Localizar todos los inputs excepto los de tipo hidden
    List<WebElement> inputsVisibles = driver.findElements(By.cssSelector("input:not([type='hidden'])"));
    
    // Localizar botones que no tengan la clase "disabled"
    List<WebElement> botonesActivos = driver.findElements(By.cssSelector("button:not(.disabled)"));
    
    // Localizar divs que no contengan la clase "oculto"
    List<WebElement> divsVisibles = driver.findElements(By.cssSelector("div:not([class*='oculto'])"));
}

Selectores avanzados combinados

La combinación de selectores avanzados permite crear expresiones altamente específicas para escenarios complejos:

@Test
void testSelectoresAvanzadosCombinados() {
    // Localizar el primer botón habilitado dentro de un formulario específico
    WebElement primerBotonActivo = driver.findElement(
        By.cssSelector("#formulario-principal button:enabled:first-of-type")
    );
    
    // Localizar filas pares de una tabla que no estén marcadas como eliminadas
    List<WebElement> filasValidasPares = driver.findElements(
        By.cssSelector("table tr:nth-child(even):not([class*='deleted'])")
    );
    
    // Localizar elementos con atributos específicos y estado
    WebElement elementoComplejo = driver.findElement(
        By.cssSelector("input[name^='usuario'][type='text']:enabled:not([readonly])")
    );
}

Técnicas de optimización

Para maximizar la eficiencia de los selectores CSS avanzados, es recomendable seguir ciertas prácticas:

@Test
void testOptimizacionSelectores() {
    // Preferir selectores específicos sobre búsquedas amplias
    WebElement elemento = driver.findElement(
        By.cssSelector("#contenedor .lista-productos li:nth-child(5)")
    );
    
    // Utilizar atributos únicos cuando estén disponibles
    WebElement botonEspecifico = driver.findElement(
        By.cssSelector("button[data-testid='submit-form']")
    );
    
    // Combinar múltiples criterios para mayor precisión
    List<WebElement> elementosFiltrados = driver.findElements(
        By.cssSelector("div.producto:not(.agotado) button[type='button']:enabled")
    );
}

Los selectores CSS avanzados proporcionan una flexibilidad excepcional para abordar los desafíos más complejos de localización de elementos. Su dominio resulta esencial para desarrollar suites de pruebas robustas que puedan adaptarse a interfaces de usuario dinámicas y estructuras DOM complejas, manteniendo al mismo tiempo un rendimiento óptimo en la ejecución de las pruebas.

Consideraciones de rendimiento XPath vs CSS

El rendimiento de localización constituye un factor crítico en la ejecución de suites de pruebas automatizadas, especialmente cuando se manejan aplicaciones web complejas con miles de elementos. La elección entre selectores CSS y XPath puede impactar significativamente en los tiempos de ejecución y la eficiencia general de las pruebas.

Los navegadores modernos están optimizados nativamente para procesar selectores CSS, ya que forman parte fundamental del motor de renderizado. Esta optimización inherente convierte a los selectores CSS en la opción preferida para la mayoría de escenarios de localización de elementos.

Ventajas de rendimiento de CSS

Los selectores CSS aprovechan el motor de consultas CSS nativo del navegador, que ha sido optimizado durante décadas para aplicar estilos de manera eficiente. Esta optimización se traduce en tiempos de búsqueda considerablemente menores.

@Test
void testComparacionRendimientoBasico() {
    long inicioCSS = System.nanoTime();
    WebElement elementoCSS = driver.findElement(By.cssSelector(".producto[data-id='123'] button"));
    long tiempoCSS = System.nanoTime() - inicioCSS;
    
    long inicioXPath = System.nanoTime();
    WebElement elementoXPath = driver.findElement(By.xpath("//div[@class='producto'][@data-id='123']//button"));
    long tiempoXPath = System.nanoTime() - inicioXPath;
    
    System.out.printf("CSS: %d ns, XPath: %d ns%n", tiempoCSS, tiempoXPath);
}

Factores que afectan al rendimiento

La complejidad del DOM influye directamente en el rendimiento de ambos tipos de selectores. Sin embargo, el impacto varía según la estrategia de localización empleada.

Profundidad del DOM

Los selectores CSS mantienen un rendimiento más consistente incluso en estructuras DOM profundamente anidadas:

@Test
void testRendimientoProfundidadDOM() {
    // CSS mantiene eficiencia en estructuras profundas
    WebElement elementoProfundoCSS = driver.findElement(
        By.cssSelector("#contenedor .seccion .subseccion .elemento-objetivo")
    );
    
    // XPath puede degradarse con mayor profundidad
    WebElement elementoProfundoXPath = driver.findElement(
        By.xpath("//div[@id='contenedor']//div[@class='seccion']//div[@class='subseccion']//div[@class='elemento-objetivo']")
    );
}

Número de elementos coincidentes

Cuando existen múltiples elementos que coinciden parcialmente con el selector, CSS suele filtrar más eficientemente:

@Test
void testRendimientoMultiplesElementos() {
    // CSS optimiza búsquedas en listas grandes
    List<WebElement> productosCSS = driver.findElements(
        By.cssSelector(".producto:nth-child(even) .precio")
    );
    
    // XPath puede ser menos eficiente con predicados complejos
    List<WebElement> productosXPath = driver.findElements(
        By.xpath("//div[@class='producto'][position() mod 2 = 0]//span[@class='precio']")
    );
}

Casos donde XPath mantiene competitividad

Aunque CSS generalmente supera a XPath en rendimiento, existen escenarios específicos donde XPath puede resultar más eficiente o necesario.

Navegación hacia elementos padre

XPath permite navegar hacia elementos padre de manera directa, mientras que CSS requiere estrategias alternativas:

@Test
void testNavegacionElementoPadre() {
    // XPath: navegación directa al padre
    WebElement contenedorPadre = driver.findElement(
        By.xpath("//button[text()='Eliminar']/parent::div")
    );
    
    // CSS: requiere localizar el padre desde una perspectiva diferente
    WebElement botonEliminar = driver.findElement(By.cssSelector("button"));
    WebElement contenedorAlternativo = (WebElement) ((JavascriptExecutor) driver)
        .executeScript("return arguments[0].parentElement;", botonEliminar);
}

Búsquedas por contenido de texto

XPath ofrece capacidades nativas para buscar por contenido textual, mientras que CSS requiere enfoques alternativos:

@Test
void testBusquedaPorTexto() {
    // XPath: búsqueda directa por texto
    WebElement enlacePorTexto = driver.findElement(
        By.xpath("//a[contains(text(), 'Términos de servicio')]")
    );
    
    // CSS: requiere localizar y filtrar posteriormente
    List<WebElement> todosLosEnlaces = driver.findElements(By.cssSelector("a"));
    WebElement enlaceEncontrado = todosLosEnlaces.stream()
        .filter(enlace -> enlace.getText().contains("Términos de servicio"))
        .findFirst()
        .orElseThrow();
}

Optimización de selectores para rendimiento

La estructura del selector impacta significativamente en el rendimiento independientemente del tipo elegido.

Principios de optimización CSS

@Test
void testOptimizacionCSS() {
    // Preferir selectores específicos y únicos
    WebElement optimizado = driver.findElement(By.cssSelector("#formulario-login input[name='usuario']"));
    
    // Evitar selectores excesivamente genéricos
    // Menos eficiente: driver.findElement(By.cssSelector("div div div input"));
    
    // Utilizar atributos data-testid cuando estén disponibles
    WebElement conTestId = driver.findElement(By.cssSelector("[data-testid='login-button']"));
}

Técnicas de medición de rendimiento

Para evaluar objetivamente el rendimiento de diferentes estrategias de localización:

@Test
void testMedicionRendimiento() {
    int iteraciones = 100;
    
    // Medir CSS
    long totalCSS = IntStream.range(0, iteraciones)
        .mapToLong(i -> {
            long inicio = System.nanoTime();
            driver.findElement(By.cssSelector(".producto[data-id='123']"));
            return System.nanoTime() - inicio;
        })
        .sum();
    
    // Medir XPath
    long totalXPath = IntStream.range(0, iteraciones)
        .mapToLong(i -> {
            long inicio = System.nanoTime();
            driver.findElement(By.xpath("//div[@class='producto'][@data-id='123']"));
            return System.nanoTime() - inicio;
        })
        .sum();
    
    double promedioCSS = totalCSS / (double) iteraciones;
    double promedioXPath = totalXPath / (double) iteraciones;
    
    System.out.printf("Promedio CSS: %.2f ns, Promedio XPath: %.2f ns%n", 
                      promedioCSS, promedioXPath);
}

Recomendaciones estratégicas

Para maximizar el rendimiento en proyectos de automatización de pruebas:

  • Priorizar CSS como estrategia principal de localización, especialmente para elementos con atributos identificadores únicos
  • Reservar XPath para casos específicos que requieran navegación compleja o búsquedas por contenido textual
  • Implementar atributos data-testid en el desarrollo de la aplicación para facilitar selectores CSS optimizados
  • Medir regularmente el rendimiento de selectores críticos para identificar posibles degradaciones
@Test
void testEstrategiaOptima() {
    // Estrategia recomendada: CSS con atributos específicos
    WebElement elementoOptimo = driver.findElement(
        By.cssSelector("[data-testid='submit-order-button']")
    );
    
    // Alternativa CSS para casos complejos
    WebElement alternativaCSS = driver.findElement(
        By.cssSelector("#order-form .actions button:nth-of-type(2)")
    );
    
    // XPath solo cuando sea necesario
    WebElement xpathNecesario = driver.findElement(
        By.xpath("//button[preceding-sibling::input[@type='checkbox' and @checked]]")
    );
}

La elección informada entre CSS y XPath, basada en las características específicas de cada caso de uso y mediciones de rendimiento objetivas, constituye una competencia fundamental para desarrollar suites de pruebas eficientes y mantenibles. Los selectores CSS deben considerarse la opción predeterminada, reservando XPath para aquellos escenarios donde sus capacidades únicas justifiquen el potencial impacto en el rendimiento.

Aprendizajes de esta lección de Selenium

  • Comprender la sintaxis y uso de selectores CSS básicos para localizar elementos en el DOM.
  • Aprender a utilizar selectores de atributo y combinadores para crear selectores más específicos.
  • Dominar selectores CSS avanzados como pseudo-clases estructurales, de estado y selectores de negación.
  • Aplicar técnicas de optimización para mejorar el rendimiento de los selectores CSS en pruebas automatizadas.
  • Comparar el rendimiento y casos de uso entre selectores CSS y XPath para elegir la mejor estrategia de localización.

Completa este curso de Selenium y certifícate

Únete a nuestra plataforma de cursos de programación y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración